2 #ifdef MOVIETEXTURE_FFMPEG
12 #define inline //someone in ffmpeg put a bit of cpp in their headers, this seemed to fix it
17 #include "libavutil/imgutils.h"
24 #include "libavformat/avformat.h"
26 #include "libswscale/swscale.h"
30 #include "libswresample/swresample.h"
34 #include "../opengl/textures.h"
37 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
38 #define av_frame_alloc avcodec_alloc_frame
39 #define av_frame_free avcodec_free_frame
45 void SaveFrame(AVFrame *pFrame,
int width,
int height,
int nchan,
int iFrame) {
51 sprintf(szFilename,
"frame%d.ppm", iFrame);
52 pFile=fopen(szFilename,
"wb");
57 fprintf(pFile,
"P6\n%d %d\n255\n", width, height);
60 for(y=0; y<height; y++)
61 fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*nchan, pFile);
66 float fwroundf(
float val){
70 singv = val < 0.0f ? -1.0f : 1.0f;
79 struct fw_movietexture {
85 int width,height,nchan,nframes,fps;
86 unsigned char **frames;
88 unsigned char *audio_buf;
94 int movie_load_from_file(
char *fname,
void **opaque){
96 struct fw_movietexture fw_movie;
97 AVFormatContext *pFormatCtx;
98 int i, videoStream, audioStream;
99 AVCodecContext *pCodecCtxOrig;
100 AVCodecContext *pCodecCtx;
101 AVCodecContext *aCodecCtxOrig;
102 AVCodecContext *aCodecCtx;
108 unsigned int audio_buf_size;
109 unsigned int audio_buf_index;
112 int audio_resample_target_fmt;
113 int do_audio_resample;
114 struct SwsContext *sws_ctx;
119 Stack *fw_framequeue;
135 if(avformat_open_input(&pFormatCtx, fname, NULL, NULL)!=0)
139 if(avformat_find_stream_info(pFormatCtx, NULL)<0)
143 av_dump_format(pFormatCtx, 0, fname, 0);
146 pCodecCtxOrig = NULL;
152 for(i=0; i<pFormatCtx->nb_streams; i++){
153 if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && videoStream < 0) {
156 if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && audioStream < 0) {
160 if(videoStream==-1 && audioStream == -1)
166 memset(&fw_movie,0,
sizeof(
struct fw_movietexture));
167 fw_movie.frames = NULL;
168 fw_movie.nframes = 0;
169 fw_movie.audio_buf = NULL;
170 fw_movie.audio_buf_size = 0;
173 aCodecCtxOrig = NULL;
180 audio_buf_size = 1000000;
184 audio_resample_target_fmt = 0;
185 do_audio_resample = FALSE;
188 if(audioStream > -1){
189 AVCodecParameters *aparams;
191 aCodecCtxOrig=pFormatCtx->streams[audioStream]->codec;
192 aCodec = avcodec_find_decoder(aCodecCtxOrig->codec_id);
194 fprintf(stderr,
"Unsupported codec!\n");
199 aCodecCtx = avcodec_alloc_context3(aCodec);
200 aparams = avcodec_parameters_alloc();
201 avcodec_parameters_from_context(aparams, aCodecCtxOrig);
202 avcodec_parameters_to_context(aCodecCtx,aparams);
203 avcodec_parameters_free(&aparams);
210 fw_movie.channels = aCodecCtx->channels;
211 fw_movie.freq = aCodecCtx->sample_rate;
212 fw_movie.bits_per_channel = aCodecCtx->bits_per_raw_sample;
218 printf(
"bits per coded channel=%d\n",aCodecCtx->bits_per_coded_sample);
221 if(avcodec_open2(aCodecCtx, aCodec, NULL) < 0){
222 fprintf(stderr,
"Could not open codec\n");
227 audio_buf = malloc(audio_buf_size);
228 aFrame=av_frame_alloc();
229 aFrameB=av_frame_alloc();
232 audio_resample_target_fmt = aCodecCtx->sample_fmt;
233 if(aCodecCtx->sample_fmt != AV_SAMPLE_FMT_S16) {
234 fw_movie.channels = 2;
235 fw_movie.freq = 44100;
236 fw_movie.bits_per_channel = 16;
237 audio_resample_target_fmt = AV_SAMPLE_FMT_S16;
238 do_audio_resample = TRUE;
255 swr = swr_alloc_set_opts(NULL,
259 aCodecCtx->channel_layout,
260 aCodecCtx->sample_fmt,
261 aCodecCtx->sample_rate,
273 fw_framequeue = NULL;
277 if(videoStream > -1){
278 AVCodecParameters *vparams;
283 pCodecCtxOrig = pFormatCtx->streams[videoStream]->codec;
287 pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
289 fprintf(stderr,
"Unsupported codec!\n");
293 pCodecCtx = avcodec_alloc_context3(pCodec);
294 vparams = avcodec_parameters_alloc();
295 avcodec_parameters_from_context(vparams, pCodecCtxOrig);
296 avcodec_parameters_to_context(pCodecCtx, vparams);
297 avcodec_parameters_free(&vparams);
303 if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
309 pFrame=av_frame_alloc();
312 pFrameRGB=av_frame_alloc();
319 av_pix_fmt = AV_PIX_FMT_RGB24;
322 av_pix_fmt = AV_PIX_FMT_RGBA;
325 fw_movie.nchan = nchan;
326 fw_movie.width = pCodecCtx->width;
327 fw_movie.height = pCodecCtx->height;
331 numBytes = av_image_get_buffer_size(av_pix_fmt, pCodecCtx->width, pCodecCtx->height,1);
332 buffer=(uint8_t *)av_malloc(numBytes*
sizeof(uint8_t));
340 av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize,buffer,av_pix_fmt,pCodecCtx->width, pCodecCtx->height,1);
343 sws_ctx = sws_getContext(pCodecCtx->width,
356 fw_framequeue = newStack(
unsigned char *);
361 while(av_read_frame(pFormatCtx, &packet)>=0) {
363 if(packet.stream_index==videoStream) {
366 avcodec_send_packet(pCodecCtx,&packet);
367 frameFinished = avcodec_receive_frame(pCodecCtx,pFrame) == 0? TRUE : FALSE;
371 unsigned char * fw_frame;
373 sws_scale(sws_ctx, (uint8_t
const *
const *)pFrame->data,
374 pFrame->linesize, 0, pCodecCtx->height,
375 pFrameRGB->data, pFrameRGB->linesize);
381 SaveFrame(pFrameRGB, pCodecCtx->width,
382 pCodecCtx->height, nchan, i);
387 fw_frame = malloc(fw_movie.height * fw_movie.width * nchan);
389 for(k=0;k<pCodecCtx->height;k++){
392 kk = pCodecCtx->height - k - 1;
393 ks = k*pFrame->linesize[0]*nchan;
394 kd = kk * fw_movie.width * nchan;
395 src = ((
unsigned char *)pFrameRGB->data[0]) + ks;
396 memcpy(&fw_frame[kd],src,fw_movie.width * nchan);
398 stack_push(
unsigned char *,fw_framequeue,fw_frame);
401 }
else if(packet.stream_index==audioStream) {
413 avcodec_send_packet(aCodecCtx, &packet);
414 got_frame = avcodec_receive_frame(aCodecCtx, aFrame) == 0 ? TRUE : FALSE;
416 buf_size = audio_buf_size - audio_buf_index;
419 if(aFrame->nb_samples > 0){
420 data_size = av_samples_get_buffer_size(NULL,
428 if(data_size * 2 > buf_size){
429 audio_buf = realloc(audio_buf,audio_buf_size *2);
432 if (do_audio_resample)
439 int nb_samples = aFrame->nb_samples;
440 int channels = aFrame->channels;
441 int outputBufferLen = nb_samples * channels * 2;
442 short* outputBuffer = (
short*)&audio_buf[audio_buf_index];
444 for (i = 0; i < nb_samples; i++)
446 for (c = 0; c < channels; c++)
448 float* extended_data = (
float*)aFrame->extended_data[c];
449 float sample = extended_data[i];
450 if (sample < -1.0f) sample = -1.0f;
451 else if (sample > 1.0f) sample = 1.0f;
452 outputBuffer[i * channels + c] = (short)fwroundf(sample * 32767.0f);
455 audio_buf_index += outputBufferLen;
461 int in_samples = aFrame->nb_samples;
463 int out_samples = (int)av_rescale_rnd(swr_get_delay(swr, aCodecCtx->sample_rate) + in_samples, 44100, aCodecCtx->sample_rate, AV_ROUND_UP);
464 av_samples_alloc(&output, NULL, 2, out_samples, AV_SAMPLE_FMT_S16, 0);
465 out_samples = swr_convert(swr,&output,out_samples, aFrame->extended_data, aFrame->nb_samples);
466 memcpy(&audio_buf[audio_buf_index],output, out_samples * 2 * 2);
467 audio_buf_index += out_samples * 2 * 2;
475 memcpy(&audio_buf[audio_buf_index], aFrame->data[0], data_size);
476 audio_buf_index += data_size;
488 if(videoStream > -1){
489 fw_movie.frames = fw_framequeue->data;
490 fw_movie.nframes = fw_framequeue->n;
491 fw_movie.duration = (double)(fw_movie.nframes) / 30.0;
498 ttip->x = fw_movie.width;
499 ttip->y = fw_movie.height;
502 ttip->channels = nchan;
504 for(k=0;k<fw_movie.nframes;k++){
506 ttip->texdata = fw_movie.frames[k];
507 sprintf(namebuf,
"%s%d.web3dit",
"ffmpeg_frame_",k);
508 saveImage_web3dit(ttip, namebuf);
515 av_frame_free(&pFrameRGB);
518 av_frame_free(&pFrame);
521 avcodec_close(pCodecCtx);
522 avcodec_close(pCodecCtxOrig);
525 if(audioStream > -1){
526 fw_movie.audio_buf = audio_buf;
527 fw_movie.audio_buf_size = audio_buf_index;
528 fw_movie.duration = (double)(fw_movie.nframes) / 30.0;
530 avcodec_close(aCodecCtxOrig);
531 avcodec_close(aCodecCtx);
536 avformat_close_input(&pFormatCtx);
537 *opaque = malloc(
sizeof(
struct fw_movietexture));
538 memcpy(*opaque,&fw_movie,
sizeof(
struct fw_movietexture));
543 double movie_get_duration(
void *opaque){
544 struct fw_movietexture *fw_movie = (
struct fw_movietexture *)opaque;
545 return fw_movie->duration;
548 unsigned char *movie_get_frame_by_fraction(
void *opaque,
float fraction,
int *width,
int *height,
int *nchan){
550 struct fw_movietexture *fw_movie = (
struct fw_movietexture *)opaque;
551 if(!fw_movie)
return NULL;
553 iframe = (int)(fraction * ((
float)(fw_movie->nframes -1) + .5f));
554 iframe = max(0,iframe);
555 iframe = min(fw_movie->nframes -1,iframe);
556 *width = fw_movie->width;
557 *height = fw_movie->height;
558 *nchan = fw_movie->nchan;
559 return fw_movie->frames[iframe];
561 unsigned char * movie_get_audio_PCM_buffer(
void *opaque,
int *freq,
int *channels,
int *size,
int *bits){
562 struct fw_movietexture *fw_movie = (
struct fw_movietexture *)opaque;
563 if(!fw_movie)
return NULL;
564 if(!fw_movie->audio_buf)
return NULL;
565 *freq = fw_movie->freq;
566 *channels = fw_movie->channels;
567 *size = fw_movie->audio_buf_size;
568 *bits = fw_movie->bits_per_channel;
569 return fw_movie->audio_buf;
571 void movie_free(
void *opaque){
572 struct fw_movietexture *fw_movie = (
struct fw_movietexture *)opaque;
575 for(k=0;k<fw_movie->nframes;k++){
576 FREE_IF_NZ(fw_movie->frames[k]);
582 #endif //MOVIETEXTURE_FFMPEG