source: libsrc/libbioimg/formats/mpeg/FfmpegOVideo.cpp @ 224:c63528c41fc2

Last change on this file since 224:c63528c41fc2 was 224:c63528c41fc2, checked in by Dmitry Fedorov <fedorov@…>, 9 years ago

building fixes

File size: 33.4 KB
Line 
1// $Date: 2008-11-17 17:39:15 -0500 (Mon, 17 Nov 2008) $
2// $Revision: 706 $
3
4/*
5videoIO: granting easy, flexible, and efficient read/write access to video
6                 files in Matlab on Windows and GNU/Linux platforms.
7   
8Copyright (c) 2006 Gerald Dalley
9 
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files (the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions:
16
17    Portions of this software link to code licensed under the Gnu General
18    Public License (GPL).  As such, they must be licensed by the more
19    restrictive GPL license rather than this MIT license.  If you compile
20    those files, this library and any code of yours that uses it automatically
21    becomes subject to the GPL conditions.  Any source files supplied by
22    this library that bear this restriction are clearly marked with internal
23    comments.
24
25The above copyright notice and this permission notice shall be included in all
26copies or substantial portions of the Software.
27
28THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34SOFTWARE.
35*/
36
37#include <errno.h>
38#include "FfmpegOVideo.h"
39#include "registry.h"
40#include "parse.h"
41#include "FfmpegCommon.h"
42#include <iostream>
43
44using namespace std;
45
46#if (LIBAVUTIL_VERSION_MAJOR >= 51)
47#define PKT_FLAG_KEY AV_PKT_FLAG_KEY
48#endif
49
50namespace VideoIO
51{
52 
53  /////////////////////////////////////////////////////////////////////////////
54  // defaults
55
56  // For a default, assume 256-QAM encoding is used (as of Oct 2008, QAM
57  // encoding is the most common DRM-free cable-based transmission standard.
58  // 256-QAM is the highest-quality mpeg2 standard).
59  static const int     DEFAULT_BITRATE_PER_PIX = (int)(38.8*1024*1024/1920/1080);
60  static const CodecID CODEC_ID_DEFAULT = CODEC_ID_MPEG1VIDEO; 
61  static const int     DEFAULT_BITRATE  = 4000000;
62  static const int     DEFAULT_WIDTH    =    352;
63  static const int     DEFAULT_HEIGHT   =    288;
64  static const int     USE_DEFAULT_VAL  =     -1;
65
66  /////////////////////////////////////////////////////////////////////////////
67  // codec id <-> codec name mappings
68
69  class stringcaseless {
70  public:
71    inline bool operator() (string const &a, string const &b) const {
72      return strcasecmp(a.c_str(), b.c_str()) < 0;
73    }
74  };
75
76  static map<CodecID,string> codecNameFromId;
77  static map<string,CodecID,stringcaseless> codecIdFromName;
78
79  static void buildCodecMaps()
80  {
81#define PC(cn) \
82      codecIdFromName[#cn]           = CODEC_ID_##cn; \
83      codecNameFromId[CODEC_ID_##cn] = #cn
84    PC(DEFAULT);
85   
86
87#if (LIBAVCODEC_VERSION_MAJOR >= 54)
88    PC(MPEG1VIDEO);     PC(MPEG2VIDEO);    PC(MPEG2VIDEO_XVMC);    PC(H261);    PC(H263);    PC(RV10);
89    PC(RV20);    PC(MJPEG);    PC(MJPEGB);    PC(LJPEG);    PC(SP5X);    PC(JPEGLS);    PC(MPEG4);
90    PC(RAWVIDEO);    PC(MSMPEG4V1);    PC(MSMPEG4V2);    PC(MSMPEG4V3);    PC(WMV1);    PC(WMV2);
91    PC(H263P);    PC(H263I);    PC(FLV1);    PC(SVQ1);    PC(SVQ3);    PC(DVVIDEO);    PC(HUFFYUV);
92    PC(CYUV);    PC(H264);    PC(INDEO3);    PC(VP3);    PC(THEORA);    PC(ASV1);    PC(ASV2);
93    PC(FFV1);    PC(4XM);    PC(VCR1);    PC(CLJR);    PC(MDEC);    PC(ROQ);    PC(INTERPLAY_VIDEO);
94    PC(XAN_WC3);    PC(XAN_WC4);    PC(RPZA);    PC(CINEPAK);    PC(WS_VQA);    PC(MSRLE);
95    PC(MSVIDEO1);    PC(IDCIN);    PC(8BPS);    PC(SMC);    PC(FLIC);    PC(TRUEMOTION1);
96    PC(VMDVIDEO);    PC(MSZH);    PC(ZLIB);    PC(QTRLE);    PC(SNOW);    PC(TSCC);
97    PC(ULTI);    PC(QDRAW);    PC(VIXL);    PC(QPEG);    PC(PNG);    PC(PPM);    PC(PBM);    PC(PGM);
98    PC(PGMYUV);    PC(PAM);    PC(FFVHUFF);    PC(RV30);    PC(RV40);    PC(VC1);    PC(WMV3);    PC(LOCO);
99    PC(WNV1);    PC(AASC);    PC(INDEO2);    PC(FRAPS);    PC(TRUEMOTION2);    PC(BMP);    PC(CSCD);    PC(MMVIDEO);
100    PC(ZMBV);    PC(AVS);    PC(SMACKVIDEO);    PC(NUV);    PC(KMVC);    PC(FLASHSV);    PC(CAVS);
101    PC(JPEG2000);    PC(VMNC);    PC(VP5);    PC(VP6);    PC(VP6F);    PC(TARGA);    PC(DSICINVIDEO);
102    PC(TIERTEXSEQVIDEO);    PC(TIFF);    PC(GIF);    PC(DXA);    PC(DNXHD);    PC(THP);    PC(SGI);
103    PC(C93);    PC(BETHSOFTVID);    PC(PTX);    PC(TXD);    PC(VP6A);    PC(AMV);    PC(VB);    PC(PCX);
104    PC(SUNRAST);    PC(INDEO4);    PC(INDEO5);    PC(MIMIC);    PC(RL2);    PC(ESCAPE124);    PC(DIRAC);
105    PC(BFI);    PC(CMV);    PC(MOTIONPIXELS);    PC(TGV);    PC(TGQ);    PC(TQI);    PC(AURA);    PC(AURA2);
106    PC(V210X);    PC(TMV);    PC(V210);    PC(DPX);    PC(MAD);    PC(FRWU);    PC(FLASHSV2);    PC(CDGRAPHICS);
107    PC(R210);    PC(ANM);    PC(BINKVIDEO);    PC(IFF_ILBM);    PC(IFF_BYTERUN1);    PC(KGV1);    PC(YOP);
108    PC(VP8);    PC(PICTOR);    PC(ANSI);    PC(A64_MULTI);    PC(A64_MULTI5);    PC(R10K);    PC(MXPEG);
109    PC(LAGARITH);    PC(PRORES);    PC(JV);    PC(DFA);    PC(WMV3IMAGE);    PC(VC1IMAGE);    PC(UTVIDEO);
110    PC(BMV_VIDEO);    PC(VBLE);    PC(DXTORY);    PC(V410);    PC(XWD);    PC(CDXL);    PC(XBM);
111    PC(ZEROCODEC);    PC(MSS1);    PC(MSA1);    PC(TSCC2);    PC(MTS2);    PC(CLLC);
112    //PC(MSS2);
113#else
114    PC(MPEG1VIDEO);     PC(MPEG2VIDEO);     PC(MPEG2VIDEO_XVMC);      PC(H261);    PC(H263);           PC(RV10);       
115    PC(RV20);    PC(MJPEG);    PC(MJPEGB);         PC(LJPEG);          PC(SP5X);                 PC(MPEG4);    PC(RAWVIDEO);   
116    PC(MSMPEG4V1);      PC(MSMPEG4V2);            PC(MSMPEG4V3);    PC(WMV1);           PC(WMV2);           PC(H263P);           
117    PC(H263I);    PC(FLV1);           PC(SVQ1);           PC(SVQ3);                 PC(DVVIDEO);    PC(HUFFYUV);   
118    PC(CYUV);           PC(H264);                 PC(INDEO3);    PC(VP3);            PC(THEORA);         PC(ASV1);             
119    PC(ASV2);    PC(FFV1);           PC(4XM);            PC(VCR1);                 PC(CLJR);    PC(MDEC);       
120    PC(ROQ);            PC(INTERPLAY_VIDEO);      PC(XAN_WC3);    PC(XAN_WC4);        PC(RPZA);           PC(CINEPAK);         
121    PC(WS_VQA);    PC(MSRLE);          PC(MSVIDEO1);       PC(IDCIN);                PC(8BPS);    PC(SMC);       
122    PC(FLIC);           PC(TRUEMOTION1);          PC(VMDVIDEO);    PC(MSZH);           PC(ZLIB);           PC(QTRLE);           
123    PC(SNOW);    PC(TSCC);           PC(ULTI);           PC(QDRAW);                PC(VIXL);    PC(QPEG);           //PC(XVID);
124    PC(PNG);                  PC(PPM);    PC(PBM);            PC(PGM);            PC(PGMYUV);               PC(PAM);
125    PC(FFVHUFF);        PC(RV30);           PC(RV40);                 PC(WMV3);           PC(LOCO);           PC(VC1);
126    PC(WNV1);           PC(AASC);    PC(INDEO2);         PC(FRAPS);          PC(TRUEMOTION2);
127#endif
128
129#undef PC
130  }
131
132  static CodecID parseCodecId(string const &cn) {
133    if (codecIdFromName.size() == 0) buildCodecMaps();
134
135    const char *codecName = cn.c_str();
136    if (codecName == NULL) return AV_CODEC_ID_NONE;
137
138    map<string,CodecID,stringcaseless>::const_iterator i = codecIdFromName.find(cn);
139    if (i == codecIdFromName.end()) return AV_CODEC_ID_NONE;
140    return i->second;
141  }
142
143  static string getCodecName(CodecID id) {
144    if (codecIdFromName.size() == 0) buildCodecMaps();
145
146    map<CodecID,string>::const_iterator i = codecNameFromId.find(id);
147    if (i == codecNameFromId.end()) return "NONE";
148    return i->second;
149  }
150
151  /////////////////////////////////////////////////////////////////////////////
152  // video manager
153
154  class FfmpegOVideoManager : public OVideoManager
155  {
156  public:
157    virtual OVideo *createVideo() throw() { 
158      return new(nothrow) FfmpegOVideo(); 
159    }
160   
161    virtual std::set<std::string> getcodecs() throw() {
162      return getFfmpegOutputCodecNames();
163    }
164  };
165 
166  static auto_ptr<OVideoManager> oldManager(
167    registerOVideoManager(new FfmpegOVideoManager()));
168 
169/////////////////////////////////////////////////////////////////////////////
170// FfmpegOVideo
171
172  FfmpegOVideo::FfmpegOVideo() : 
173    fpsNum(30000), fpsDenom(1001),
174    bitRate(USE_DEFAULT_VAL), bitRateTolerance(USE_DEFAULT_VAL),
175    gopSize(USE_DEFAULT_VAL), maxBFrames(USE_DEFAULT_VAL), 
176    width(USE_DEFAULT_VAL), height(USE_DEFAULT_VAL), 
177    codecId(CODEC_ID_DEFAULT), 
178    fmt(NULL), oc(NULL), videoStream(NULL), currFrameNum(-1), rgbPicture(NULL),
179    codecPicture(NULL), outputBuffer(NULL), 
180    urlOpened(false), codecOpened(false)
181#ifdef VIDEO_READER_USE_SWSCALER
182    , imgConvertCtx(NULL)
183#endif
184  { }
185
186// (S)et (P)arameter if file is (C)onfigurable
187#define SPC(pa) if (kvm.hasKey(#pa)) { pa = kvm.parseInt<int>(#pa); }
188
189  void FfmpegOVideo::setup(KeyValueMap &kvm)
190  {
191     TRACE;
192     avcodec_register_all();
193     if (!isConfigurable()) close();
194     
195     int fpsNum, fpsDenom;
196     if (kvm.fpsParse(fpsNum, fpsDenom)) {
197       setFramesPerSecond(fpsNum, fpsDenom);
198     }
199
200     SPC(bitRate);
201     SPC(bitRateTolerance);
202     SPC(width);
203     SPC(height);
204     SPC(gopSize);
205     SPC(maxBFrames);
206
207     KeyValueMap::const_iterator cdc = kvm.find("codec");
208     if (cdc != kvm.end()) {
209       CodecID newCodecId = parseCodecId(cdc->second);
210       VrRecoverableCheckMsg(newCodecId != AV_CODEC_ID_NONE,
211                             "The \"" << cdc->second << "\" codec is not "
212                             "recognized by your version of ffmpeg.");
213       if (newCodecId != AV_CODEC_ID_NONE) {
214         setCodec(newCodecId);
215       }
216     }
217       
218     KeyValueMap::const_iterator fname = kvm.find("filename");
219     if (fname != kvm.end()) {
220       open(fname->second);
221     }
222
223     //kvm.alertUncheckedKeys("Unrecognized arguments: "); // dima, probably not very important
224  }
225
226#define assnString(lval, x) \
227  { stringstream ss; ss << x; lval = ss.str(); }
228
229  KeyValueMap FfmpegOVideo::getSetupAndStats() const {
230    TRACE;
231    KeyValueMap kvm;
232    // setup
233    assnString(kvm["fps"],              getFramesPerSecond());
234    assnString(kvm["bitRate"],          getBitRate());
235    assnString(kvm["bitRateTolerance"], getBitRateTolerance());
236    assnString(kvm["width"],            getWidth());
237    assnString(kvm["height"],           getHeight());
238    assnString(kvm["depth"],            getDepth());
239    assnString(kvm["gopSize"],          getGopSize());
240    assnString(kvm["maxBFrames"],       getMaxBFrames());
241    assnString(kvm["codec"],            getCodecName());
242               kvm["filename"]        = oc ? oc->filename : "";
243
244    // stats
245    assnString(kvm["currFrameNum"], currFrameNum); 
246
247    return kvm;
248  }
249
250  string FfmpegOVideo::getCodecName() const {
251    return VideoIO::getCodecName(getCodec());
252  }
253
254  static inline int64_t frameToTimestamp(AVCodecContext const *pCodecCtx, 
255                                         int64_t frame)
256  {
257  #if LIBAVCODEC_VERSION_INT < ((51<<16)+(7<<8)+0)
258    return (int64_t)(1000 * frame * 
259                   pCodecCtx->frame_rate_base / pCodecCtx->frame_rate);
260  #else
261    return (int64_t)(1000 * frame * 
262                   pCodecCtx->time_base.num / pCodecCtx->time_base.den);
263  #endif
264  }
265 
266  static inline int64_t timestampToFrame(AVCodecContext const *pCodecCtx, 
267                                         int64_t ts)
268  {
269  #if LIBAVCODEC_VERSION_INT < ((51<<16)+(7<<8)+0)
270    int64_t f = (int64_t)(ts * pCodecCtx->frame_rate / 
271                      1000 / pCodecCtx->frame_rate_base);
272  #else
273    int64_t f = (int64_t)(ts * pCodecCtx->time_base.den /
274                      1000 / pCodecCtx->time_base.num);
275  #endif
276    // Provide consistent handling of roundoff errors.  Example: at 30fps,
277    // frame 10 --> 333.333...ms, which gets rounded down to 333ms.
278    // If we then say timestampToFrame(...,333), we get frame 9, not
279    // frame 10.  We choose to make the frame numbers authoritative
280    // and we make timestamp rounding consistent with the frame numbers.
281    if (ts == frameToTimestamp(pCodecCtx, f+1)) f++;
282    return f;
283  }
284
285  /** Converts Matlab's preferred byte layout for images to C-style RGB images.
286   *  This code should be kept in sync with bgr2Matlab in FfmpegIVideo.cpp.
287   */
288  static inline void matlab2rgb(unsigned char *rgb, unsigned char const *mat, 
289    int w, int h, int d)
290  {
291    for (int c=0; c<d; c++) {
292      for (int x=0; x<w; x++) {
293        for (int y=0; y<h; y++) {
294          // We need to transpose from row-major to column-major
295          rgb[(x+y*w)*d + c] = *mat++;
296        }
297      }
298    }
299  }
300
301  void FfmpegOVideo::open(std::string const &fname)
302  {
303    TRACE;
304    // initialize libavcodec, and register all codecs and formats
305    ffmpegInitIfNeeded();
306
307    if (isOpen()) close();
308
309    VERBOSE("Opening video file (" << fname << ") for writing...");
310
311    try {
312      // auto detect the output format from the name. default is mpeg.
313      #if (LIBAVCODEC_VERSION_MAJOR >= 54)
314      if (formatName.size() > 0)
315        fmt = av_guess_format(formatName.c_str(), NULL, NULL);
316      else
317        fmt = av_guess_format(NULL, fname.c_str(), NULL); 
318      #else
319      if (formatName.size() > 0)
320        fmt = guess_format(formatName.c_str(), NULL, NULL);
321      else
322        fmt = guess_format(NULL, fname.c_str(), NULL);
323      #endif
324      if (!fmt) {
325        // Could not deduce output format from file extension: using MPEG.
326        #if (LIBAVCODEC_VERSION_MAJOR >= 54)
327        fmt = av_guess_format("mpeg", NULL, NULL);
328        #else
329        fmt = guess_format("mpeg", NULL, NULL);
330        #endif
331      }
332      VrRecoverableCheckMsg(fmt != NULL, 
333        "Could not allocate even the default file format descriptor for \"" << 
334        fname << "\".  Is your memory corrupted?");
335
336      if (codecId == AV_CODEC_ID_NONE)
337        codecId = fmt->video_codec;
338
339      // allocate the output media context
340      #if (LIBAVCODEC_VERSION_MAJOR >= 54)
341      VrRecoverableCheckMsg(oc = avformat_alloc_context(), 
342        "Could not allocate the output media descriptor for \"" << fname <<
343        "\".  Are you out of memory?");
344      #else
345      VrRecoverableCheckMsg(oc = av_alloc_format_context(), 
346        "Could not allocate the output media descriptor for \"" << fname <<
347        "\".  Are you out of memory?");
348      #endif
349
350      oc->oformat = fmt;
351      snprintf(oc->filename, sizeof(oc->filename), "%s", fname.c_str());
352
353      // add the video streams using the default format codecs
354      // and initialize the codecs
355      VrRecoverableCheckMsg(fmt->video_codec != AV_CODEC_ID_NONE, 
356        "Unable to determine the system default codec for \"" << fname << 
357        "\".");
358     
359      if (codecId != AV_CODEC_ID_NONE)
360        fmt->video_codec = codecId;
361
362      currFrameNum = -1;
363    } catch (VrRecoverableException const &e) {
364      close();
365      throw;
366    } catch (VrFatalError const &e) {
367      close();
368      throw;
369    }
370  }
371
372  /* Attempts to encode the frame pointed to by codecPicture.
373   * If codecPicture==NULL, this can be used to drain the encoder
374   * in preparation of closing the file.  Upon success, returns
375   * the number of encoded bytes written to oc.  If 0, this
376   * means that the encoder has buffered data that can be
377   * drained later by subsequent calls to encodeFrame.  On
378   * error, a negative value is returned.
379   */
380  static int encodeFrame(AVFormatContext *oc, AVCodecContext *c, AVStream *st,
381                         uint8 *outputBuffer, int OutputBufferSize, 
382                         AVFrame *codecPicture)
383  {
384    TRACE;
385    VERBOSE("c=" << c << ", outputBuffer=" << outputBuffer << " (" << 
386            OutputBufferSize << " bytes), codecPicture=" << 
387            codecPicture);
388
389    /* encode the image */
390    int nEncodedBytes = avcodec_encode_video(c, outputBuffer, 
391                                             OutputBufferSize, codecPicture);
392    VERBOSE("nEncodedBytes = " << nEncodedBytes);
393
394    /* if zero size, it means the image was buffered */
395    if (nEncodedBytes > 0) {
396      AVPacket pkt;
397      av_init_packet(&pkt);
398
399#if LIBAVCODEC_VERSION_INT < ((51<<16)+(7<<8)+0)
400      if (st->r_frame_rate_base==0) {
401        pkt.pts = 0; 
402      } else {
403        AVRational bb = {c->frame_rate_base, c->frame_rate};
404        AVRational cc =  {st->r_frame_rate_base, st->r_frame_rate};
405        pkt.pts = av_rescale_q(c->coded_frame->pts, bb, cc);
406      }
407#else
408      pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, 
409                             st->time_base);
410#endif
411      if(c->coded_frame->key_frame) pkt.flags |= PKT_FLAG_KEY;
412      pkt.stream_index = st->index;
413      pkt.data         = outputBuffer;
414      pkt.size         = nEncodedBytes; 
415     
416      /* write the compressed frame in the media file */
417      if (av_write_frame(oc, &pkt) < 0) return -1;
418    }
419   
420    return nEncodedBytes;
421  }
422
423  void FfmpegOVideo::close() 
424  {
425    TRACE;
426
427    VERBOSE("Draining the encoder...");
428    if (oc && videoStream && getCodecFromStream(videoStream) && outputBuffer) {
429      // Do I need a check for (oc->oformat->flags & AVFMT_RAWPICTURE)?
430      while (encodeFrame(oc, getCodecFromStream(videoStream), videoStream, 
431                         outputBuffer, OutputBufferSize, NULL) > 0);
432    }
433
434    VERBOSE("Closing video codec...");
435    if (videoStream && codecOpened) {
436      AVCodecContext *c = getCodecFromStream(videoStream);
437      if ((c != NULL) && (avcodec_find_encoder(c->codec_id) != NULL)) {
438        avcodec_close(getCodecFromStream(videoStream));
439      }
440    }
441    videoStream = NULL;
442    codecOpened = false;
443
444    VERBOSE("Freeing the pictures and buffers...");
445    if (codecPicture) {
446      av_free(codecPicture->data[0]);
447      av_free(codecPicture);
448      codecPicture = NULL;
449    }
450    if (rgbPicture) {
451      av_free(rgbPicture->data[0]);
452      av_free(rgbPicture);
453      rgbPicture = NULL;
454    }
455    if (outputBuffer) {
456      av_free(outputBuffer);
457      outputBuffer = NULL;
458    }
459   
460    if (oc && urlOpened) {
461      VERBOSE("Writing the trailer (if applicable)...");
462      av_write_trailer(oc);
463
464      VERBOSE("Freeing the streams...");
465      for (int i = 0; i < oc->nb_streams; i++) {
466#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(7<<8)+0)
467        av_freep(&oc->streams[i]->codec);
468#endif
469        av_freep(&oc->streams[i]);
470      }
471     
472      if (!(fmt->flags & AVFMT_NOFILE)) {
473        VERBOSE("Closing the output file...");
474#if LIBAVFORMAT_VERSION_MAJOR >= 54
475        avio_close(oc->pb);
476#elif LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0)
477        url_fclose(oc->pb);
478#else
479        url_fclose(&oc->pb);
480#endif
481      }
482
483      VERBOSE("Freeing the format context...");
484      av_free(oc);
485      oc = NULL;
486    }
487    urlOpened = false;
488   
489    currFrameNum = -1;
490
491#ifdef VIDEO_READER_USE_SWSCALER
492    VERBOSE("Cleaning up the image converter...");
493    if (imgConvertCtx != NULL) {
494      sws_freeContext(imgConvertCtx);
495      imgConvertCtx = NULL;
496    }
497#endif
498  }
499
500
501  static void writeVideoFrame(
502#ifdef VIDEO_READER_USE_SWSCALER
503                              struct SwsContext *&imgConvertCtx, 
504                              int rgbW, int rgbH,
505#endif
506                              AVFormatContext *oc, AVStream *st, 
507                              int currFrameNum, AVFrame *rgbPicture,
508                              AVFrame *codecPicture, 
509                              uint8 *outputBuffer, int OutputBufferSize)
510  {
511    TRACE;
512    AVCodecContext *c = getCodecFromStream(st);
513
514    // rgbPicture is in RGB24, so we must convert it to the codec pixel format
515#ifdef VIDEO_READER_USE_SWSCALER
516    imgConvertCtx = sws_getCachedContext(imgConvertCtx,
517                                         rgbW, rgbH, PIX_FMT_RGB24,
518                                         c->width, c->height, c->pix_fmt,
519                                         SWS_POINT, NULL, NULL, NULL);
520    VrRecoverableCheckMsg(imgConvertCtx, 
521      "Could not initialize the colorspace converter to convert from RGB to "
522      "the codec's colorspace.");
523    FfRecoverableCheckMsg(
524      sws_scale(imgConvertCtx, 
525                rgbPicture->data, rgbPicture->linesize, 0, rgbH, 
526                codecPicture->data, codecPicture->linesize),
527      "Could not convert from RGB to the stream's pixel format.");
528#else
529    FfRecoverableCheck(img_convert((AVPicture*)codecPicture, c->pix_fmt, 
530                       (AVPicture*)rgbPicture, PIX_FMT_RGB24,
531                       c->width, c->height));
532#endif
533   
534    if (oc->oformat->flags & AVFMT_RAWPICTURE) {
535      /* raw video case. The API will change slightly in the near
536         futur for that */
537      AVPacket pkt;
538      av_init_packet(&pkt);
539
540      pkt.flags |= PKT_FLAG_KEY;
541      pkt.stream_index = st->index;
542      pkt.data         = (uint8_t *)codecPicture;
543      pkt.size         = sizeof(AVPicture);
544
545      FfRecoverableCheckMsg(av_write_frame(oc, &pkt), 
546        "Could not write frame " << currFrameNum << ".  "
547        "Perhaps you are out of disk space or have lost write permissions.");
548    } else {
549      const int nEncodedBytes = encodeFrame(oc, c, st, outputBuffer, 
550                                            OutputBufferSize, codecPicture);
551      /*
552      VrRecoverableCheckMsg(nEncodedBytes >= 0,
553        "No bytes were encoded for frame " << currFrameNum << ".");
554      */
555    }
556  }
557
558  void FfmpegOVideo::addframe(int w, int h, int d,
559                              IVideo::Frame const &f) 
560  {
561    TRACE;
562    VrRecoverableCheck(isOpen());
563   
564    if (getWidth() == USE_DEFAULT_VAL)  setWidth(w);
565    if (getHeight() == USE_DEFAULT_VAL) setHeight(h);
566   
567    VrRecoverableCheck(w == getWidth());
568    VrRecoverableCheck(h == getHeight());
569    VrRecoverableCheck(d == getDepth());
570    VrRecoverableCheck(f.size() == w*h*d);
571
572    if (isConfigurable()) finalizeOpen();
573
574    try {
575      matlab2rgb(rgbPicture->data[0], &f[0], w, h, d);
576
577      writeVideoFrame(
578#ifdef VIDEO_READER_USE_SWSCALER
579                      imgConvertCtx, w, h,
580#endif
581                      oc, videoStream, ++currFrameNum, 
582                      rgbPicture, codecPicture, 
583                      outputBuffer, OutputBufferSize);
584    } catch (VrRecoverableException const &e) {
585      close();
586      throw;
587    }
588  }
589
590
591  // dima: writing without matlab stuff - addframe split into two functions
592  void FfmpegOVideo::initFromRawFrame(int w, int h, int d) {
593    TRACE;
594    VrRecoverableCheck(isOpen());
595   
596    if (getWidth() == USE_DEFAULT_VAL)  setWidth(w);
597    if (getHeight() == USE_DEFAULT_VAL) setHeight(h);
598   
599    VrRecoverableCheck(w == getWidth());
600    VrRecoverableCheck(h == getHeight());
601    VrRecoverableCheck(d == getDepth());
602
603    if (isConfigurable()) 
604      finalizeOpen();
605  }
606
607  void FfmpegOVideo::addFromRawFrame(int w, int h, int d) {
608    try {
609      writeVideoFrame(
610#ifdef VIDEO_READER_USE_SWSCALER
611                      imgConvertCtx, w, h,
612#endif
613                      oc, videoStream, ++currFrameNum, 
614                      rgbPicture, codecPicture, 
615                      outputBuffer, OutputBufferSize);
616    } catch (VrRecoverableException const &e) {
617      close();
618      throw;
619    }
620  }
621  // dima: end, writing without matlab stuff - split into two functions
622
623  void FfmpegOVideo::setFramesPerSecond(double newVal)
624  { 
625    VrRecoverableCheck(isConfigurable()); 
626    VrRecoverableCheckMsg(newVal > 0, 
627      "frame rate values must be positive (" << newVal << " requested).");
628    if (newVal == 29.97) { // ffmpeg is really picky about NTSC rates
629      fpsNum   = 30000;
630      fpsDenom =  1001;
631    } else {
632      fpsNum   = (int)(newVal * AV_TIME_BASE);
633      fpsDenom = AV_TIME_BASE;
634    }
635  }
636
637  void FfmpegOVideo::setFramesPerSecond(int num, int denom)
638  {
639    VrRecoverableCheck(isConfigurable());
640    VrRecoverableCheckMsg(num > 0 && denom > 0,
641      "frame rate values must be positive, but " << num << " / " << denom << 
642      " was supplied.");
643    fpsNum   = num;
644    fpsDenom = denom;
645  }
646
647  void FfmpegOVideo::setBitRate(int newVal)
648  { 
649    VrRecoverableCheck(isConfigurable()); 
650    bitRate = newVal; 
651  }
652
653  void FfmpegOVideo::setBitRateTolerance(int newVal)
654  { 
655    VrRecoverableCheck(isConfigurable()); 
656    bitRateTolerance = newVal; 
657  }
658
659  void FfmpegOVideo::setWidth(int newVal)
660  { 
661    VrRecoverableCheck(isConfigurable()); 
662    width = newVal; 
663  }
664
665  void FfmpegOVideo::setHeight(int newVal)
666  { 
667    VrRecoverableCheck(isConfigurable()); 
668    height = newVal; 
669  }
670
671  void FfmpegOVideo::setGopSize(int newVal)
672  { 
673    VrRecoverableCheck(isConfigurable()); 
674    gopSize = newVal; 
675  }
676
677  void FfmpegOVideo::setMaxBFrames(int newVal)
678  { 
679    VrRecoverableCheck(isConfigurable()); 
680    maxBFrames = newVal; 
681  }
682
683  void FfmpegOVideo::setCodec(CodecID newCodecId)
684  {
685    TRACE;
686    VrRecoverableCheck(isConfigurable());
687    if ((newCodecId == CODEC_ID_ASV1) || (newCodecId == CODEC_ID_ASV2) || 
688        (newCodecId == CODEC_ID_SVQ1)) {
689      VrRecoverableThrow("The " << VideoIO::getCodecName(newCodecId) << 
690                         " codec segfaults (crashes) in some versions of "
691                         "ffmpeg.  If you believe your version of ffmpeg "
692                         "has fixed this problem, please find the first "
693                         "ffmpeg version that supports it and add proper "
694                         "LIBAVCODEC_VERSION_INT ifdefs to "
695                         "FfmpegOVideo::setCodec(CodecID).\n");
696    }
697    codecId = newCodecId;
698  }
699
700  void FfmpegOVideo::setCodec(string const &codecName)
701  { 
702    CodecID newCodecId = parseCodecId(codecName);
703    VrRecoverableCheckMsg(newCodecId != AV_CODEC_ID_NONE, 
704      "No \"" << codecName << "\" codec could be found.");
705    setCodec(newCodecId);
706  }
707
708  bool FfmpegOVideo::isOpen() const 
709  { 
710    return fmt && oc;// && videoStream && rgbPicture && codecPicture &&
711    //outputBuffer && urlOpened && codecOpened;
712  }
713 
714  bool FfmpegOVideo::isConfigurable() const
715  {
716    return currFrameNum < 0;
717  }
718
719  #if (LIBAVUTIL_VERSION_MAJOR >= 50)
720  static AVFrame *allocPicture(enum PixelFormat pixFmt, int width, int height)
721  #else
722  static AVFrame *allocPicture(int pixFmt, int width, int height)
723  #endif
724  {
725    TRACE;
726    AVFrame *codecPicture = avcodec_alloc_frame();
727    if (!codecPicture) return NULL;
728    const int size = avpicture_get_size(pixFmt, width, height);
729    uint8_t *codecPictureBuf = (uint8_t*)av_malloc(size);
730    if (!codecPictureBuf) {
731      av_free(codecPicture);
732      return NULL;
733    }
734    VrRecoverableCheck(
735      avpicture_fill((AVPicture *)codecPicture, codecPictureBuf,
736                     pixFmt, width, height) == size);
737
738    return codecPicture;
739  }
740
741  void FfmpegOVideo::finalizeOpen()
742  {
743    TRACE;
744    VrRecoverableCheck(isConfigurable());
745
746    try {
747      fmt->video_codec = codecId;
748      VrRecoverableCheck(videoStream = addVideoStream());
749
750      // set the output parameters (must be done even if no
751      // parameters).
752      //FfRecoverableCheck(av_set_parameters(oc, NULL)); // dima: depricated, now parameters are passed directly to avformat_write_header
753
754#ifdef PRINT_INFOS
755      dump_format(oc, 0, fname.c_str(), 1);
756#endif
757
758      // now that all the parameters are set, we can open the
759      // video codecs and allocate the necessary encode buffers
760      openVideo();
761
762      // open the output file, if needed
763      if (!(fmt->flags & AVFMT_NOFILE)) {
764        #if LIBAVFORMAT_VERSION_MAJOR >= 54
765        FfRecoverableCheckMsg(
766          avio_open(&oc->pb, oc->filename, AVIO_FLAG_WRITE), 
767          "Could not open \"" << oc->filename << "\" for writing.");
768        #else
769        FfRecoverableCheckMsg(
770          url_fopen(&oc->pb, oc->filename, URL_WRONLY), 
771          "Could not open \"" << oc->filename << "\" for writing.");
772        #endif
773        urlOpened = true;
774      }
775
776      // write the stream header, if any
777      FfRecoverableCheckMsg(avformat_write_header(oc, NULL), 
778                            "Could not write file header for \"" << 
779                            oc->filename);
780     
781    } catch (VrRecoverableException const &e) {
782      close();
783      throw;
784    } catch (VrFatalError const &e) {
785      close();
786      throw;
787    }
788  }
789
790  void FfmpegOVideo::openVideo()
791  {
792    TRACE;
793    AVCodecContext *c = getCodecFromStream(videoStream);
794    VrRecoverableCheck(c != NULL);
795
796    //dima: attempt to fix h264 encoding
797    if (c->codec_id == AV_CODEC_ID_H264) {
798      c->me_range = 16;
799      c->max_qdiff = 4;
800      c->qmin = 10;
801      c->qmax = 51;
802      c->qcompress = 0.6; 
803    }
804    //dima: attempt to fix h264 encoding
805
806    VERBOSE("Finding the video encoder...");
807    AVCodec *codec = avcodec_find_encoder(c->codec_id);
808    VrRecoverableCheckMsg(codec != NULL, 
809                          "Could not find a(n) " << getCodecName() << 
810                          " encoder");
811
812    VERBOSE("Selecting the pixel format...");
813    if (codec && codec->pix_fmts){
814      const enum PixelFormat *p= codec->pix_fmts;
815      for(; *p!=-1; p++){
816        if (*p == c->pix_fmt) break;
817      }
818      if (*p == -1) c->pix_fmt = codec->pix_fmts[0];
819    }
820
821    VERBOSE("Opening the codec...");
822    #if (LIBAVCODEC_VERSION_MAJOR >= 54)
823    FfRecoverableCheckMsg(avcodec_open2(c, codec, NULL),
824                          "Could not initialize the codec.  "
825                          "Perhaps you've chosen an unsupported frame rate.");
826    #else
827    FfRecoverableCheckMsg(avcodec_open(c, codec),
828                          "Could not initialize the codec.  "
829                          "Perhaps you've chosen an unsupported frame rate.");
830    #endif
831
832    // When avcodec_open fails, it tends to leave a mess, so we use a flag
833    // to tell us if it succeeded.  There a chance that our close method will
834    // leak memory on failed avcodec_open attempts.
835    codecOpened = true;
836
837    outputBuffer = NULL;
838    if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
839      VERBOSE("Allocating the output buffer...");
840      VrRecoverableCheck(outputBuffer = (uint8*)av_malloc(OutputBufferSize));
841    }
842
843    VERBOSE("Allocating the encoded raw codec picture...");
844    VrRecoverableCheck(
845      codecPicture = allocPicture(c->pix_fmt, c->width, c->height));
846   
847    VERBOSE("Allocating input image wrapper...");
848    VrRecoverableCheckMsg(
849      rgbPicture = allocPicture(PIX_FMT_RGB24, c->width, c->height),
850      "Could not allocate a " << c->width << "x" << c->height << 
851      " RGB image.  Perhaps you are out of memory.");   
852  }
853
854#define SETINTVAL(varname, fieldname) \
855  if (varname != USE_DEFAULT_VAL) {   \
856    c->fieldname = varname;           \
857  }
858
859#define SETINTVALDEFAULT(varname, fieldname, defaultVal) \
860  if (varname != USE_DEFAULT_VAL) {                      \
861    c->fieldname = varname;                              \
862  } else {                                               \
863    c->fieldname = defaultVal;                           \
864  }
865
866  AVStream *FfmpegOVideo::addVideoStream()
867  {
868    TRACE;
869    AVCodecContext *c;
870    AVStream *st;
871   
872    if (fpsNum   <= 0) return NULL;
873    if (fpsDenom <= 0) return NULL;
874    if (getWidth()  <= 0) return NULL;
875    if (getHeight() <= 0) return NULL;
876   
877    const int videoStreamIdx = 0;
878    st = av_new_stream(oc, videoStreamIdx);
879    if (!st) return NULL;
880
881    c = getCodecFromStream(st);
882    c->codec_id   = codecId;
883    c->codec_type = CODEC_TYPE_VIDEO;
884#if (LIBAVCODEC_VERSION_INT > 0x000409) || (LIBAVCODEC_VERSION_INT == 0x000409 && LIBAVCODEC_BUILD >= 4753)
885    c->pix_fmt    = PIX_FMT_NONE; // let the codec decide
886#else
887    // PIX_FMT_NONE wasn't introduced until svn revision 4161
888    c->pix_fmt    = (PixelFormat)-1;
889#endif
890
891    // dima, set particular fourcc
892    if (video_codec_tag)
893      c->codec_tag = video_codec_tag;
894
895    // Set encoder params.  See AVCodecContext docs in avcodec.h for details.
896    // We could expand the set of supported params further.
897    SETINTVAL       (width,            width);
898    SETINTVAL       (height,           height);
899    SETINTVAL       (gopSize,          gop_size); 
900    SETINTVAL       (maxBFrames,       max_b_frames);
901    SETINTVALDEFAULT(bitRate,          bit_rate, width*height*DEFAULT_BITRATE_PER_PIX);
902    SETINTVAL       (bitRateTolerance, bit_rate_tolerance);
903   
904#if LIBAVCODEC_VERSION_INT < ((51<<16)+(7<<8)+0)
905    c->frame_rate_base = fpsDenom;
906    c->frame_rate      = fpsNum;
907#else
908    c->time_base.num   = fpsDenom;
909    c->time_base.den   = fpsNum;
910#endif
911
912    if (c->codec_id == CODEC_ID_MPEG1VIDEO){
913      // needed to avoid using macroblocks in which some coeffs overflow
914      // this doesnt happen with normal video, it just happens here as the
915      // motion of the chroma plane doesnt match the luma plane
916      c->mb_decision = FF_MB_DECISION_RD;
917    }
918   
919    // some formats want stream headers to be seperate
920    if (strcmp(oc->oformat->name, "mp4")==0 || 
921        strcmp(oc->oformat->name, "mov")==0 || 
922        strcmp(oc->oformat->name, "3gp")==0) {
923      c->flags |= CODEC_FLAG_GLOBAL_HEADER; 
924    }
925   
926    return st;
927  }
928};
Note: See TracBrowser for help on using the repository browser.