4 // Class for writing movies from Aven for old libav/ffmpeg
6 // Copyright (C) 2004,2011,2012,2013,2014,2015,2016 Olly Betts
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 /* Based on output-example.c:
25 * Libavformat API example: Output a media file in any supported
26 * libavformat format. The default codecs are used.
28 * Copyright (c) 2003 Fabrice Bellard
30 * Permission is hereby granted, free of charge, to any person obtaining a copy
31 * of this software and associated documentation files (the "Software"), to deal
32 * in the Software without restriction, including without limitation the rights
33 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34 * copies of the Software, and to permit persons to whom the Software is
35 * furnished to do so, subject to the following conditions:
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
53 #define __STDC_CONSTANT_MACROS
59 #include "moviemaker.h"
63 # include <libavutil/imgutils.h>
64 # include <libavutil/mathematics.h>
65 # include <libavformat/avformat.h>
66 # include <libswscale/swscale.h>
68 # ifndef AV_PKT_FLAG_KEY
69 # define AV_PKT_FLAG_KEY PKT_FLAG_KEY
71 # ifndef HAVE_AV_GUESS_FORMAT
72 # define av_guess_format guess_format
74 # ifndef HAVE_AVIO_OPEN
75 # define avio_open url_fopen
77 # ifndef HAVE_AVIO_CLOSE
78 # define avio_close url_fclose
80 # ifndef HAVE_AV_FRAME_ALLOC
81 static inline AVFrame
* av_frame_alloc() {
82 return avcodec_alloc_frame();
85 # ifndef HAVE_AV_FRAME_FREE
86 # ifdef HAVE_AVCODEC_FREE_FRAME
87 static inline void av_frame_free(AVFrame
** frame
) {
88 avcodec_free_frame(frame
);
91 static inline void av_frame_free(AVFrame
** frame
) {
92 free((*frame
)->data
[0]);
98 # ifndef HAVE_AVCODEC_OPEN2
99 // We always pass NULL for OPTS below.
100 # define avcodec_open2(CTX, CODEC, OPTS) avcodec_open(CTX, CODEC)
102 # ifndef HAVE_AVFORMAT_NEW_STREAM
103 // We always pass NULL for CODEC below.
104 # define avformat_new_stream(S, CODEC) av_new_stream(S, 0)
106 # if !HAVE_DECL_AVMEDIA_TYPE_VIDEO
107 # define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
109 # if !HAVE_DECL_AV_CODEC_ID_NONE
110 # define AV_CODEC_ID_NONE CODEC_ID_NONE
112 # if !HAVE_DECL_AV_PIX_FMT_RGB24
113 # define AV_PIX_FMT_RGB24 PIX_FMT_RGB24
115 # if !HAVE_DECL_AV_PIX_FMT_YUV420P
116 # define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
118 # ifndef AVIO_FLAG_WRITE
119 # define AVIO_FLAG_WRITE URL_WRONLY
123 MOVIE_NO_SUITABLE_FORMAT
= 1,
125 MOVIE_FILENAME_TOO_LONG
128 # ifndef HAVE_AVCODEC_ENCODE_VIDEO2
129 const int OUTBUF_SIZE
= 200000;
133 MovieMaker::MovieMaker()
135 : oc(0), video_st(0), frame(0), outbuf(0), pixels(0), sws_ctx(0), averrno(0)
139 static bool initialised_ffmpeg
= false;
140 if (initialised_ffmpeg
) return;
142 // FIXME: register only the codec(s) we want to use...
143 avcodec_register_all();
146 initialised_ffmpeg
= true;
152 write_packet(void *opaque
, uint8_t *buf
, int buf_size
) {
153 FILE * fh
= (FILE*)opaque
;
154 size_t res
= fwrite(buf
, 1, buf_size
, fh
);
155 return res
> 0 ? res
: -1;
159 seek_stream(void *opaque
, int64_t offset
, int whence
) {
160 FILE * fh
= (FILE*)opaque
;
161 return fseek(fh
, offset
, whence
);
165 #define MAX_EXTENSION_LEN 8
167 bool MovieMaker::Open(FILE* fh
, const char * ext
, int width
, int height
)
172 AVOutputFormat
* fmt
= NULL
;
173 char dummy_filename
[MAX_EXTENSION_LEN
+ 3] = "x.";
174 if (strlen(ext
) <= MAX_EXTENSION_LEN
) {
175 strcpy(dummy_filename
+ 2, ext
);
176 // Pass "x." + extension to av_guess_format() to avoid having to deal
177 // with wide character filenames.
178 fmt
= av_guess_format(NULL
, dummy_filename
, NULL
);
181 // We couldn't deduce the output format from file extension so default
183 fmt
= av_guess_format("mpeg", NULL
, NULL
);
185 averrno
= MOVIE_NO_SUITABLE_FORMAT
;
188 strcpy(dummy_filename
+ 2, "mpg");
190 if (fmt
->video_codec
== AV_CODEC_ID_NONE
) {
191 averrno
= MOVIE_AUDIO_ONLY
;
195 /* Allocate the output media context. */
196 oc
= avformat_alloc_context();
198 averrno
= AVERROR(ENOMEM
);
202 strcpy(oc
->filename
, dummy_filename
);
204 /* find the video encoder */
205 AVCodec
*codec
= avcodec_find_encoder(fmt
->video_codec
);
207 // FIXME : Erm - internal ffmpeg library problem?
208 averrno
= AVERROR(ENOMEM
);
212 // Add the video stream.
213 video_st
= avformat_new_stream(oc
, codec
);
215 averrno
= AVERROR(ENOMEM
);
219 // Set sample parameters.
220 AVCodecContext
*c
= video_st
->codec
;
221 c
->bit_rate
= 400000;
222 /* Resolution must be a multiple of two. */
225 /* timebase: This is the fundamental unit of time (in seconds) in terms
226 * of which frame timestamps are represented. For fixed-fps content,
227 * timebase should be 1/framerate and timestamp increments should be
229 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(55, 44, 0)
230 // Old way, which now causes deprecation warnings.
231 c
->time_base
.den
= 25; // Frames per second.
232 c
->time_base
.num
= 1;
234 video_st
->time_base
.den
= 25; // Frames per second.
235 video_st
->time_base
.num
= 1;
236 c
->time_base
= video_st
->time_base
;
238 c
->gop_size
= 12; /* emit one intra frame every twelve frames at most */
239 c
->pix_fmt
= AV_PIX_FMT_YUV420P
;
240 c
->rc_buffer_size
= c
->bit_rate
* 4; // Enough for 4 seconds
241 c
->rc_max_rate
= c
->bit_rate
* 2;
242 // B frames are backwards predicted - they can improve compression,
243 // but may slow encoding and decoding.
244 // if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
245 // c->max_b_frames = 2;
248 /* Some formats want stream headers to be separate. */
249 if (oc
->oformat
->flags
& AVFMT_GLOBALHEADER
)
250 c
->flags
|= CODEC_FLAG_GLOBAL_HEADER
;
253 #ifndef HAVE_AVFORMAT_WRITE_HEADER
254 // Set the output parameters (must be done even if no parameters).
255 retval
= av_set_parameters(oc
, NULL
);
262 retval
= avcodec_open2(c
, NULL
, NULL
);
268 #ifndef HAVE_AVCODEC_ENCODE_VIDEO2
270 if (!(oc
->oformat
->flags
& AVFMT_RAWPICTURE
)) {
271 outbuf
= (unsigned char *)av_malloc(OUTBUF_SIZE
);
273 averrno
= AVERROR(ENOMEM
);
279 /* Allocate the encoded raw picture. */
280 frame
= av_frame_alloc();
282 averrno
= AVERROR(ENOMEM
);
285 retval
= av_image_alloc(frame
->data
, frame
->linesize
,
286 c
->width
, c
->height
, c
->pix_fmt
, 1);
292 if (c
->pix_fmt
!= AV_PIX_FMT_YUV420P
) {
293 // FIXME need to allocate another frame for this case if we stop
294 // hardcoding AV_PIX_FMT_YUV420P.
298 frame
->format
= c
->pix_fmt
;
299 frame
->width
= c
->width
;
300 frame
->height
= c
->height
;
302 pixels
= (unsigned char *)av_malloc(width
* height
* 6);
304 averrno
= AVERROR(ENOMEM
);
308 // Show the format we've ended up with (for debug purposes).
309 // av_dump_format(oc, 0, fnm, 1);
312 sws_ctx
= sws_getContext(width
, height
, AV_PIX_FMT_RGB24
,
313 width
, height
, c
->pix_fmt
, SWS_BICUBIC
,
315 if (sws_ctx
== NULL
) {
316 fprintf(stderr
, "Cannot initialize the conversion context!\n");
317 averrno
= AVERROR(ENOMEM
);
321 if (!(fmt
->flags
& AVFMT_NOFILE
)) {
322 const int buf_size
= 8192;
323 void * buf
= av_malloc(buf_size
);
324 oc
->pb
= avio_alloc_context(static_cast<uint8_t*>(buf
), buf_size
, 1,
325 fh
, NULL
, write_packet
, seek_stream
);
327 averrno
= AVERROR(ENOMEM
);
332 // Write the stream header, if any.
333 #ifdef HAVE_AVFORMAT_WRITE_HEADER
334 retval
= avformat_write_header(oc
, NULL
);
336 retval
= av_write_header(oc
);
354 unsigned char * MovieMaker::GetBuffer() const {
356 return pixels
+ GetWidth() * GetHeight() * 3;
362 int MovieMaker::GetWidth() const {
365 AVCodecContext
*c
= video_st
->codec
;
372 int MovieMaker::GetHeight() const {
375 AVCodecContext
*c
= video_st
->codec
;
382 bool MovieMaker::AddFrame()
385 AVCodecContext
* c
= video_st
->codec
;
387 if (c
->pix_fmt
!= AV_PIX_FMT_YUV420P
) {
392 int len
= 3 * c
->width
;
394 // Flip image vertically
396 unsigned char * src
= pixels
+ h
* len
;
397 unsigned char * dest
= src
- len
;
399 memcpy(dest
, src
, len
);
404 sws_scale(sws_ctx
, &pixels
, &len
, 0, c
->height
, frame
->data
, frame
->linesize
);
406 if (oc
->oformat
->flags
& AVFMT_RAWPICTURE
) {
410 // Encode this frame.
411 #ifdef HAVE_AVCODEC_ENCODE_VIDEO2
414 av_init_packet(&pkt
);
417 int ret
= avcodec_encode_video2(c
, &pkt
, frame
, &got_packet
);
422 if (got_packet
&& pkt
.size
) {
423 // Write the compressed frame to the media file.
424 if (pkt
.pts
!= int64_t(AV_NOPTS_VALUE
)) {
425 pkt
.pts
= av_rescale_q(pkt
.pts
,
426 c
->time_base
, video_st
->time_base
);
428 if (pkt
.dts
!= int64_t(AV_NOPTS_VALUE
)) {
429 pkt
.dts
= av_rescale_q(pkt
.dts
,
430 c
->time_base
, video_st
->time_base
);
432 pkt
.stream_index
= video_st
->index
;
434 /* Write the compressed frame to the media file. */
435 ret
= av_interleaved_write_frame(oc
, &pkt
);
442 out_size
= avcodec_encode_video(c
, outbuf
, OUTBUF_SIZE
, frame
);
443 // outsize == 0 means that this frame has been buffered, so there's nothing
446 // Write the compressed frame to the media file.
448 av_init_packet(&pkt
);
450 if (c
->coded_frame
->pts
!= (int64_t)AV_NOPTS_VALUE
)
451 pkt
.pts
= av_rescale_q(c
->coded_frame
->pts
, c
->time_base
, video_st
->time_base
);
452 if (c
->coded_frame
->key_frame
)
453 pkt
.flags
|= AV_PKT_FLAG_KEY
;
454 pkt
.stream_index
= video_st
->index
;
458 /* Write the compressed frame to the media file. */
459 int ret
= av_interleaved_write_frame(oc
, &pkt
);
474 if (video_st
&& averrno
== 0) {
475 // No more frames to compress. The codec may have a few frames
476 // buffered if we're using B frames, so write those too.
477 AVCodecContext
* c
= video_st
->codec
;
479 #ifdef HAVE_AVCODEC_ENCODE_VIDEO2
483 av_init_packet(&pkt
);
487 int ret
= avcodec_encode_video2(c
, &pkt
, NULL
, &got_packet
);
493 if (!got_packet
) break;
494 if (!pkt
.size
) continue;
496 // Write the compressed frame to the media file.
497 if (pkt
.pts
!= int64_t(AV_NOPTS_VALUE
)) {
498 pkt
.pts
= av_rescale_q(pkt
.pts
,
499 c
->time_base
, video_st
->time_base
);
501 if (pkt
.dts
!= int64_t(AV_NOPTS_VALUE
)) {
502 pkt
.dts
= av_rescale_q(pkt
.dts
,
503 c
->time_base
, video_st
->time_base
);
505 pkt
.stream_index
= video_st
->index
;
507 /* Write the compressed frame to the media file. */
508 ret
= av_interleaved_write_frame(oc
, &pkt
);
517 out_size
= avcodec_encode_video(c
, outbuf
, OUTBUF_SIZE
, NULL
);
519 // Write the compressed frame to the media file.
521 av_init_packet(&pkt
);
523 if (c
->coded_frame
->pts
!= (int64_t)AV_NOPTS_VALUE
)
524 pkt
.pts
= av_rescale_q(c
->coded_frame
->pts
, c
->time_base
, video_st
->time_base
);
525 if (c
->coded_frame
->key_frame
)
526 pkt
.flags
|= AV_PKT_FLAG_KEY
;
527 pkt
.stream_index
= video_st
->index
;
531 /* write the compressed frame in the media file */
532 int ret
= av_interleaved_write_frame(oc
, &pkt
);
542 av_write_trailer(oc
);
552 MovieMaker::release()
556 avcodec_close(video_st
->codec
);
561 av_frame_free(&frame
);
572 for (size_t i
= 0; i
< oc
->nb_streams
; ++i
) {
573 av_freep(&oc
->streams
[i
]->codec
);
574 av_freep(&oc
->streams
[i
]);
577 if (!(oc
->oformat
->flags
& AVFMT_NOFILE
)) {
578 // Release the AVIOContext.
593 MovieMaker::~MovieMaker()
601 MovieMaker::get_error_string() const
608 return "Number syntax expected in filename";
609 case AVERROR_INVALIDDATA
:
610 /* same as AVERROR_UNKNOWN: return "unknown error"; */
611 return "invalid data found";
612 case AVERROR(ENOMEM
):
613 return "not enough memory";
614 case AVERROR(EILSEQ
):
615 return "unknown format";
616 case AVERROR(ENOSYS
):
617 return "Operation not supported";
618 case AVERROR(ENOENT
):
619 return "No such file or directory";
621 return "End of file";
622 case AVERROR_PATCHWELCOME
:
623 return "Not implemented in FFmpeg";
626 case MOVIE_NO_SUITABLE_FORMAT
:
627 return "Couldn't find a suitable output format";
628 case MOVIE_AUDIO_ONLY
:
629 return "Audio-only format specified";
630 case MOVIE_FILENAME_TOO_LONG
:
631 return "Filename too long";
634 return "Unknown error";