Some FFmpeg changes
[blender.git] / source / gameengine / VideoTexture / VideoFFmpeg.cpp
index f827475..1ba944a 100644 (file)
@@ -1,7 +1,4 @@
-/** \file gameengine/VideoTexture/VideoFFmpeg.cpp
- *  \ingroup bgevideotex
- */
-/* $Id$
+/*
 -----------------------------------------------------------------------------
 This source file is part of VideoTexture library
 
@@ -23,6 +20,11 @@ http://www.gnu.org/copyleft/lesser.txt.
 -----------------------------------------------------------------------------
 */
 
+/** \file gameengine/VideoTexture/VideoFFmpeg.cpp
+ *  \ingroup bgevideotex
+ */
+
+
 #ifdef WITH_FFMPEG
 
 // INT64_C fix for some linux machines (C99ism)
@@ -37,8 +39,8 @@ http://www.gnu.org/copyleft/lesser.txt.
 
 #include <string>
 
-#include "Exception.h"
 #include "VideoFFmpeg.h"
+#include "Exception.h"
 
 
 // default framerate
@@ -50,8 +52,6 @@ const long timeScale = 1000;
 #define CATCH_EXCP catch (Exception & exp) \
 { exp.report(); m_status = SourceError; }
 
-extern "C" void do_init_ffmpeg();
-
 // class RenderVideo
 
 // constructor
@@ -160,17 +160,17 @@ void VideoFFmpeg::initParams (short width, short height, float rate, bool image)
 }
 
 
-int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVFormatParameters *formatParams)
+int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVDictionary **formatParams)
 {
-       AVFormatContext *formatCtx;
+       AVFormatContext *formatCtx = NULL;
        int                             i, videoStream;
        AVCodec                 *codec;
        AVCodecContext  *codecCtx;
 
-       if(av_open_input_file(&formatCtx, filename, inputFormat, 0, formatParams)!=0)
+       if (avformat_open_input(&formatCtx, filename, inputFormat, formatParams)!=0)
                return -1;
 
-       if(av_find_stream_info(formatCtx)<0) 
+       if (av_find_stream_info(formatCtx)<0) 
        {
                av_close_input_file(formatCtx);
                return -1;
@@ -178,9 +178,9 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
 
        /* Find the first video stream */
        videoStream=-1;
-       for(i=0; i<formatCtx->nb_streams; i++)
+       for (i=0; i<formatCtx->nb_streams; i++)
        {
-               if(formatCtx->streams[i] &&
+               if (formatCtx->streams[i] &&
                        get_codec_from_stream(formatCtx->streams[i]) && 
                        (get_codec_from_stream(formatCtx->streams[i])->codec_type==AVMEDIA_TYPE_VIDEO))
                {
@@ -189,7 +189,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
                }
        }
 
-       if(videoStream==-1) 
+       if (videoStream==-1) 
        {
                av_close_input_file(formatCtx);
                return -1;
@@ -199,20 +199,20 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
 
        /* Find the decoder for the video stream */
        codec=avcodec_find_decoder(codecCtx->codec_id);
-       if(codec==NULL) 
+       if (codec==NULL) 
        {
                av_close_input_file(formatCtx);
                return -1;
        }
        codecCtx->workaround_bugs = 1;
-       if(avcodec_open(codecCtx, codec)<0) 
+       if (avcodec_open(codecCtx, codec)<0) 
        {
                av_close_input_file(formatCtx);
                return -1;
        }
 
 #ifdef FFMPEG_OLD_FRAME_RATE
-       if(codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1)
+       if (codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1)
                codecCtx->frame_rate_base=1000;
        m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
 #else
@@ -292,7 +292,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
 /*
  * This thread is used to load video frame asynchronously.
  * It provides a frame caching service. 
- * The main thread is responsible for positionning the frame pointer in the
+ * The main thread is responsible for positioning the frame pointer in the
  * file correctly before calling startCache() which starts this thread.
  * The cache is organized in two layers: 1) a cache of 20-30 undecoded packets to keep
  * memory and CPU low 2) a cache of 5 decoded frames. 
@@ -371,7 +371,7 @@ void *VideoFFmpeg::cacheThread(void *data)
                                avcodec_decode_video2(video->m_codecCtx, 
                                        video->m_frame, &frameFinished, 
                                        &cachePacket->packet);
-                               if(frameFinished) 
+                               if (frameFinished) 
                                {
                                        AVFrame * input = video->m_frame;
 
@@ -519,8 +519,6 @@ void VideoFFmpeg::releaseFrame(AVFrame* frame)
 // open video file
 void VideoFFmpeg::openFile (char * filename)
 {
-       do_init_ffmpeg();
-
        if (openStream(filename, NULL, NULL) != 0)
                return;
 
@@ -543,12 +541,8 @@ void VideoFFmpeg::openFile (char * filename)
                // but it is really not desirable to seek on http file, so force streaming.
                // It would be good to find this information from the context but there are no simple indication
                !strncmp(filename, "http://", 7) ||
-#ifdef FFMPEG_PB_IS_POINTER
-        (m_formatCtx->pb && m_formatCtx->pb->is_streamed)
-#else
-        m_formatCtx->pb.is_streamed
-#endif
-        )
+               (m_formatCtx->pb && !m_formatCtx->pb->seekable)
+               )
        {
                // the file is in fact a streaming source, treat as cam to prevent seeking
                m_isFile = false;
@@ -584,13 +578,10 @@ void VideoFFmpeg::openCam (char * file, short camIdx)
 {
        // open camera source
        AVInputFormat           *inputFormat;
-       AVFormatParameters      formatParams;
-       AVRational                      frameRate;
-       char                            *p, filename[28], rateStr[20];
+       AVDictionary            *formatParams = NULL;
+       char                            filename[28], rateStr[20];
+       char                *p;
 
-       do_init_ffmpeg();
-
-       memset(&formatParams, 0, sizeof(formatParams));
 #ifdef WIN32
        // video capture on windows only through Video For Windows driver
        inputFormat = av_find_input_format("vfwcap");
@@ -607,7 +598,7 @@ void VideoFFmpeg::openCam (char * file, short camIdx)
        // The driver name is constructed automatically from the device type:
        // v4l   : /dev/video<camIdx>
        // dv1394: /dev/dv1394/<camIdx>
-       // If you have different driver name, you can specify the driver name explicitely 
+       // If you have different driver name, you can specify the driver name explicitly
        // instead of device type. Examples of valid filename:
        //    /dev/v4l/video0:pal
        //    /dev/ieee1394/1:ntsc
@@ -620,7 +611,13 @@ void VideoFFmpeg::openCam (char * file, short camIdx)
                sprintf(filename, "/dev/dv1394/%d", camIdx);
        } else 
        {
-               inputFormat = av_find_input_format("video4linux");
+               const char *formats[] = {"video4linux2,v4l2", "video4linux2", "video4linux"};
+               int i, formatsCount = sizeof(formats) / sizeof(char*);
+               for (i = 0; i < formatsCount; i++) {
+                       inputFormat = av_find_input_format(formats[i]);
+                       if (inputFormat)
+                               break;
+               }
                sprintf(filename, "/dev/video%d", camIdx);
        }
        if (!inputFormat)
@@ -634,20 +631,22 @@ void VideoFFmpeg::openCam (char * file, short camIdx)
                if ((p = strchr(filename, ':')) != 0)
                        *p = 0;
        }
-       if (file && (p = strchr(file, ':')) != NULL)
-               formatParams.standard = p+1;
+       if (file && (p = strchr(file, ':')) != NULL) {
+               av_dict_set(&formatParams, "standard", p+1, 0);
+       }
 #endif
        //frame rate
        if (m_captRate <= 0.f)
                m_captRate = defFrameRate;
        sprintf(rateStr, "%f", m_captRate);
-       av_parse_video_rate(&frameRate, rateStr);
-       // populate format parameters
-       // need to specify the time base = inverse of rate
-       formatParams.time_base.num = frameRate.den;
-       formatParams.time_base.den = frameRate.num;
-       formatParams.width = m_captWidth;
-       formatParams.height = m_captHeight;
+
+       av_dict_set(&formatParams, "framerate", rateStr, 0);
+
+       if (m_captWidth > 0 && m_captHeight > 0) {
+               char video_size[64];
+               BLI_snprintf(video_size, sizeof(video_size), "%dx%d", m_captWidth, m_captHeight);
+               av_dict_set(&formatParams, "video_size", video_size, 0);
+       }
 
        if (openStream(filename, inputFormat, &formatParams) != 0)
                return;
@@ -662,6 +661,8 @@ void VideoFFmpeg::openCam (char * file, short camIdx)
                // no need to thread if the system has a single core
                m_isThreaded =  true;
        }
+
+       av_dict_free(&formatParams);
 }
 
 // play video
@@ -791,7 +792,7 @@ void VideoFFmpeg::calcImage (unsigned int texId, double ts)
                {
                        AVFrame* frame;
                        // get image
-                       if((frame = grabFrame(actFrame)) != NULL)
+                       if ((frame = grabFrame(actFrame)) != NULL)
                        {
                                if (!m_isFile && !m_cacheStarted) 
                                {
@@ -842,7 +843,7 @@ void VideoFFmpeg::setPositions (void)
                m_startTime -= double(m_lastFrame) / actFrameRate();
        else {
                m_startTime -= m_range[0];
-               // start from begining, stop cache just in case
+               // start from beginning, stop cache just in case
                stopCache();
        }
 }
@@ -957,7 +958,7 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
                                // of the file.
                                if (position <= m_preseek)
                                {
-                                       // we can safely go the begining of the file
+                                       // we can safely go the beginning of the file
                                        if (av_seek_frame(m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_BYTE) >= 0)
                                        {
                                                // binary seek does not reset the timestamp, must do it now
@@ -997,7 +998,7 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
        // return the next frame. This is not quite correct, may need more work
        while(av_read_frame(m_formatCtx, &packet)>=0) 
        {
-               if(packet.stream_index == m_videoStream) 
+               if (packet.stream_index == m_videoStream) 
                {
                        avcodec_decode_video2(m_codecCtx, 
                                m_frame, &frameFinished, 
@@ -1186,7 +1187,7 @@ static PyGetSetDef videoGetSets[] =
        {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
        {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
        {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
-       {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
+       {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
        {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
        {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
        {(char*)"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, (char*)"nb of frames of preseek", NULL},
@@ -1307,7 +1308,7 @@ static PyGetSetDef imageGetSets[] =
        {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
        {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
        {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
-       {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
+       {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
        {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
        {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
        {NULL}