stereoplay

diff src/vid.c @ 0:265a24704ff2

stereoplay
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 06 Mar 2011 20:31:18 +0200
parents
children fd671d488cfd
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/vid.c	Sun Mar 06 20:31:18 2011 +0200
     1.3 @@ -0,0 +1,157 @@
     1.4 +#include <stdio.h>
     1.5 +#include <libavcodec/avcodec.h>
     1.6 +#include <libavformat/avformat.h>
     1.7 +#include <libswscale/swscale.h>
     1.8 +#include "vid.h"
     1.9 +
    1.10 +struct video_file {
    1.11 +	AVFormatContext *avctx;
    1.12 +	AVCodecContext *cctx;
    1.13 +	AVCodec *codec;
    1.14 +	int vstream, audio_stream;
    1.15 +	struct SwsContext *sws;
    1.16 +
    1.17 +	AVFrame *frm, *rgbfrm;
    1.18 +};
    1.19 +
    1.20 +struct video_file *vid_open(const char *fname)
    1.21 +{
    1.22 +	static int initialized;
    1.23 +	struct video_file *vf;
    1.24 +	int i;
    1.25 +
    1.26 +	if(!initialized) {
    1.27 +		av_register_all();
    1.28 +		initialized = 1;
    1.29 +	}
    1.30 +
    1.31 +	if(!(vf = malloc(sizeof *vf))) {
    1.32 +		fprintf(stderr, "open_video(%s): failed to allocate memory: %s\n", fname, strerror(errno));
    1.33 +		return 0;
    1.34 +	}
    1.35 +	memset(vf, 0, sizeof *vf);
    1.36 +
    1.37 +	if(av_open_input_file(&vf->avctx, fname, 0, 0, 0) != 0) {
    1.38 +		fprintf(stderr, "open_video(%s): failed to open file\n", fname);
    1.39 +		vid_close(vf);
    1.40 +		return 0;
    1.41 +	}
    1.42 +
    1.43 +	if(av_find_stream_info(vf->avctx) < 0) {
    1.44 +		fprintf(stderr, "open_video(%s): failed to find stream info\n", fname);
    1.45 +		vid_close(vf);
    1.46 +		return 0;
    1.47 +	}
    1.48 +
    1.49 +	vf->vstream = -1;
    1.50 +	for(i=0; i<vf->avctx->nb_streams; i++) {
    1.51 +		if(vf->avctx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
    1.52 +			vf->vstream = i;
    1.53 +			break;
    1.54 +		}
    1.55 +	}
    1.56 +	if(vf->vstream == -1) {
    1.57 +		fprintf(stderr, "open_video(%s): didn't find a video stream\n", fname);
    1.58 +		vid_close(vf);
    1.59 +		return 0;
    1.60 +	}
    1.61 +	vf->cctx = vf->avctx->streams[vf->vstream]->codec;
    1.62 +
    1.63 +	if(!(vf->codec = avcodec_find_decoder(vf->cctx->codec_id))) {
    1.64 +		fprintf(stderr, "open_video(%s): unsupported codec\n", fname);
    1.65 +		vid_close(vf);
    1.66 +		return 0;
    1.67 +	}
    1.68 +
    1.69 +	if(avcodec_open(vf->cctx, vf->codec) < 0) {
    1.70 +		fprintf(stderr, "open_video(%s): failed to open codec\n", fname);
    1.71 +		vid_close(vf);
    1.72 +		return 0;
    1.73 +	}
    1.74 +
    1.75 +	if(!(vf->frm = avcodec_alloc_frame()) || !(vf->rgbfrm = avcodec_alloc_frame())) {
    1.76 +		fprintf(stderr, "open_video(%s): failed to allocate frame\n", fname);
    1.77 +		vid_close(vf);
    1.78 +		return 0;
    1.79 +	}
    1.80 +
    1.81 +	vf->sws = sws_getContext(vf->cctx->width, vf->cctx->height, vf->cctx->pix_fmt,
    1.82 +			vf->cctx->width, vf->cctx->height, PIX_FMT_RGB32, SWS_POINT, 0, 0, 0);
    1.83 +	if(!vf->sws) {
    1.84 +		fprintf(stderr, "open_video(%s): failed to allocate sws context\n", fname);
    1.85 +		vid_close(vf);
    1.86 +		return 0;
    1.87 +	}
    1.88 +
    1.89 +
    1.90 +	printf("using codec: %s\n", vf->codec->name);
    1.91 +	printf("fps: %f (%u usec frame interval)\n", vid_fps(vf), vid_frame_interval(vf));
    1.92 +	printf("size: %dx%d\n", vid_frame_width(vf), vid_frame_height(vf));
    1.93 +
    1.94 +	return vf;
    1.95 +}
    1.96 +
    1.97 +void vid_close(struct video_file *vf)
    1.98 +{
    1.99 +	if(!vf) return;
   1.100 +
   1.101 +	/* TODO how do we deallocate sws contexts? */
   1.102 +	if(vf->rgbfrm) av_free(vf->rgbfrm);
   1.103 +	if(vf->frm) av_free(vf->frm);
   1.104 +	if(vf->cctx) avcodec_close(vf->cctx);
   1.105 +	if(vf->avctx) av_close_input_file(vf->avctx);
   1.106 +	free(vf);
   1.107 +}
   1.108 +
   1.109 +
   1.110 +float vid_fps(struct video_file *vf)
   1.111 +{
   1.112 +	float inv_tb = (float)vf->cctx->time_base.den / (float)vf->cctx->time_base.num;
   1.113 +	return inv_tb / (float)vf->cctx->ticks_per_frame;
   1.114 +}
   1.115 +
   1.116 +unsigned int vid_frame_interval(struct video_file *vf)
   1.117 +{
   1.118 +	float fps = vid_fps(vf);
   1.119 +	return 1000000 / fps;
   1.120 +}
   1.121 +
   1.122 +int vid_frame_width(struct video_file *vf)
   1.123 +{
   1.124 +	return vf->cctx->width;
   1.125 +}
   1.126 +
   1.127 +int vid_frame_height(struct video_file *vf)
   1.128 +{
   1.129 +	return vf->cctx->height;
   1.130 +}
   1.131 +
   1.132 +size_t vid_frame_size(struct video_file *vf)
   1.133 +{
   1.134 +	return vf->cctx->width * vf->cctx->height * 4;
   1.135 +}
   1.136 +
   1.137 +int vid_get_frame(struct video_file *vf, uint32_t *img)
   1.138 +{
   1.139 +	AVPacket packet;
   1.140 +	int frame_done = 0;
   1.141 +	AVPicture *rgbfrm = (AVPicture*)vf->rgbfrm;
   1.142 +	AVPicture *frm = (AVPicture*)vf->frm;
   1.143 +
   1.144 +	avpicture_fill((AVPicture*)vf->rgbfrm, (uint8_t*)img, PIX_FMT_RGB32, vf->cctx->width, vf->cctx->height);
   1.145 +
   1.146 +	while(av_read_frame(vf->avctx, &packet) >= 0) {
   1.147 +		if(packet.stream_index == vf->vstream) {
   1.148 +			avcodec_decode_video2(vf->cctx, vf->frm, &frame_done, &packet);
   1.149 +
   1.150 +			if(frame_done) {
   1.151 +				sws_scale(vf->sws, frm->data, frm->linesize, 0, vf->cctx->height, rgbfrm->data, rgbfrm->linesize);
   1.152 +				av_free_packet(&packet);
   1.153 +				return 0;
   1.154 +			}
   1.155 +		}
   1.156 +		av_free_packet(&packet);
   1.157 +	}
   1.158 +
   1.159 +	return -1;
   1.160 +}