1 | // $Date: 2008-11-17 17:39:15 -0500 (Mon, 17 Nov 2008) $ |
---|
2 | // $Revision: 706 $ |
---|
3 | |
---|
4 | /* |
---|
5 | videoIO: granting easy, flexible, and efficient read/write access to video |
---|
6 | files in Matlab on Windows and GNU/Linux platforms. |
---|
7 | |
---|
8 | Copyright (c) 2006 Gerald Dalley |
---|
9 | |
---|
10 | Permission is hereby granted, free of charge, to any person obtaining a copy |
---|
11 | of this software and associated documentation files (the "Software"), to deal |
---|
12 | in the Software without restriction, including without limitation the rights |
---|
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
---|
14 | copies of the Software, and to permit persons to whom the Software is |
---|
15 | furnished 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 | |
---|
25 | The above copyright notice and this permission notice shall be included in all |
---|
26 | copies or substantial portions of the Software. |
---|
27 | |
---|
28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
---|
29 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
---|
30 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
---|
31 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
---|
32 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
---|
33 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
---|
34 | SOFTWARE. |
---|
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 | |
---|
44 | using namespace std; |
---|
45 | |
---|
46 | #if (LIBAVUTIL_VERSION_MAJOR >= 51) |
---|
47 | #define PKT_FLAG_KEY AV_PKT_FLAG_KEY |
---|
48 | #endif |
---|
49 | |
---|
50 | namespace 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 | }; |
---|