2 * Common Source Code Project for Qt : movie saver.
3 * (C) 2016 K.Ohta <whatisthis.sowhat _at_ gmail.com>
5 * History: May 27, 2016 : Initial. This refer from avidemux 2.5.6 .
10 #include "./csp_avio_basic.h"
11 #include "movie_saver.h"
13 #include "csp_logger.h"
19 #if defined(USE_LIBAV)
21 #include <libavutil/avassert.h>
22 #include <libavutil/channel_layout.h>
23 #include <libavutil/opt.h>
24 #include <libavutil/mathematics.h>
25 #include <libavutil/timestamp.h>
26 #include <libavformat/avformat.h>
27 #include <libswscale/swscale.h>
28 #include <libswresample/swresample.h>
30 #if (LIBAVCODEC_VERSION_MAJOR > 56)
31 #define AVCODEC_UPPER_V56
35 //int MOVIE_SAVER::write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
36 int MOVIE_SAVER::write_frame(void *_fmt_ctx, const void *_time_base, void *_st, void *_pkt)
38 #if defined(USE_LIBAV)
39 AVFormatContext *fmt_ctx = (AVFormatContext *)_fmt_ctx;
40 const AVRational *time_base = (const AVRational *)_time_base;
41 AVStream *st = (AVStream *)_st;
42 AVPacket *pkt = (AVPacket *)_pkt;
43 /* rescale output packet timestamp values from codec to stream timebase */
44 av_packet_rescale_ts(pkt, *time_base, st->time_base);
45 pkt->stream_index = st->index;
47 /* Write the compressed frame to the media file. */
48 //log_packet(fmt_ctx, pkt);
49 return av_interleaved_write_frame(fmt_ctx, pkt);
55 /* Add an output stream. */
56 bool MOVIE_SAVER::add_stream(void *_ost, void *_oc,
60 #if defined(USE_LIBAV)
62 OutputStream *ost = (OutputStream *)_ost;
63 AVFormatContext *oc = (AVFormatContext *)_oc;
64 AVCodec **codec = (AVCodec **)_codec;
65 enum AVCodecID codec_id = (enum AVCodecID)_codec_id;
66 /* find the encoder */
67 *codec = (AVCodec *)avcodec_find_encoder(codec_id);
69 out_debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not find encoder for '%s'\n",
70 (const char *)avcodec_get_name(codec_id));
74 ost->st = avformat_new_stream(oc, *codec);
76 out_debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not allocate stream\n");
79 ost->st->id = oc->nb_streams-1;
80 #ifdef AVCODEC_UPPER_V56
81 ost->context = avcodec_alloc_context3(*codec);
82 if (ost->context == NULL) {
83 out_debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Failed to allocate context for encoding: \n");
87 #ifdef AVCODEC_UPPER_V56
88 AVCodecParameters *cp = ost->st->codecpar;
92 switch ((*codec)->type) {
93 case AVMEDIA_TYPE_AUDIO:
94 cp->codec_type = AVMEDIA_TYPE_AUDIO;
95 cp->codec_id = codec_id;
96 cp->format = (*codec)->sample_fmts ? (*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
97 cp->bit_rate = audio_bit_rate;
98 cp->channel_layout = AV_CH_LAYOUT_STEREO;
100 cp->sample_rate = audio_sample_rate;
101 cp->frame_size = 1024;
103 case AVMEDIA_TYPE_VIDEO:
104 cp->codec_type = AVMEDIA_TYPE_VIDEO;
105 cp->codec_id = codec_id;
106 cp->format = STREAM_PIX_FMT;
107 cp->bit_rate = video_bit_rate;
108 cp->width = video_geometry.width();
109 cp->height = video_geometry.height();
112 cp->sample_aspect_ratio = ratio;
113 cp->field_order = AV_FIELD_PROGRESSIVE;
118 avcodec_parameters_to_context(ost->context, cp);
123 switch ((*codec)->type) {
124 case AVMEDIA_TYPE_AUDIO:
125 setup_audio(c, (void **)codec);
126 ost->st->time_base = (AVRational){ 1, c->sample_rate };
127 c->time_base = (AVRational){ 1, c->sample_rate };
129 case AVMEDIA_TYPE_VIDEO:
130 c->codec_id = codec_id;
131 c->bit_rate = video_bit_rate;
133 // https://libav.org/avconv.html#Video-Options
134 /* Resolution must be a multiple of two. */
135 c->width = video_geometry.width();
136 c->height = video_geometry.height();
137 c->thread_count = video_encode_threads;
139 /* timebase: This is the fundamental unit of time (in seconds) in terms
140 * of which frame timestamps are represented. For fixed-fps content,
141 * timebase should be 1/framerate and timestamp increments should be
143 ost->st->time_base = (AVRational){ 1, rec_fps};
144 c->time_base = ost->st->time_base;
146 //c->gop_size = rec_fps; /* emit one intra frame every one second */
147 c->pix_fmt = STREAM_PIX_FMT;
148 #ifndef AVCODEC_UPPER_V56
149 if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
150 /* just for testing, we also add B frames */
152 c->gop_size = rec_fps; /* emit one intra frame every one second */
154 if (c->codec_id == AV_CODEC_ID_MPEG4) {
155 setup_mpeg4((void *)c);
157 if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
158 /* Needed to avoid using macroblocks in which some coeffs overflow.
159 * This does not happen with normal video, it just happens here as
160 * the motion of the chroma plane does not match the luma plane. */
163 if (c->codec_id == AV_CODEC_ID_H264) {
164 setup_h264((void *)c);
168 int __type = CSP_AVIO_BASIC::csp_avio_get_codec_type((_TCHAR*)avcodec_get_name(c->codec_id));
170 case CSP_AVIO_BASIC::TYPE_MPEG1:
173 /* just for testing, we also add B frames */
174 case CSP_AVIO_BASIC::TYPE_MPEG2:
176 c->gop_size = rec_fps; /* emit one intra frame every one second */
178 case CSP_AVIO_BASIC::TYPE_MPEG4:
179 setup_mpeg4((void *)c);
181 case CSP_AVIO_BASIC::TYPE_H264:
182 case CSP_AVIO_BASIC::TYPE_LIBX264:
183 setup_h264((void *)c);
196 /* Some formats want stream headers to be separate. */
197 if (oc->oformat->flags & AVFMT_GLOBALHEADER)
198 c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
207 //void MOVIE_SAVER::close_stream(AVFormatContext *oc, OutputStream *ost)
208 void MOVIE_SAVER::close_stream(void *_oc, void *_ost)
210 #if defined(USE_LIBAV)
211 OutputStream *ost = (OutputStream *)_ost;
212 #ifdef AVCODEC_UPPER_V56
213 avcodec_close(ost->context);
214 while(avcodec_is_open(ost->context) != 0) { this->msleep(5);}
216 avcodec_close(ost->st->codec);
217 while(avcodec_is_open(ost->st->codec) != 0) { this->msleep(5);}
219 av_frame_free(&ost->frame);
220 av_frame_free(&ost->tmp_frame);
221 sws_freeContext(ost->sws_ctx);
222 swr_free(&ost->swr_ctx);
223 #ifdef AVCODEC_UPPER_V56
224 avcodec_free_context(&(ost->context));
229 void MOVIE_SAVER::do_open(QString filename, int _fps, int _sample_rate)
231 if(recording || req_close || req_stop) return;
232 if(filename.isEmpty()) return;
233 if(_fps <= 0) return;
234 if(_sample_rate <= 10) return;
235 do_set_record_fps(_fps);
236 audio_sample_rate = _sample_rate;
237 _filename = filename;
241 bool MOVIE_SAVER::do_open_main()
243 #if defined(USE_LIBAV)
244 if(req_close) return false;
245 if(req_stop) return false;
246 if(_filename.isEmpty()) return false;
247 if(rec_fps <= 0) return false;
248 if(audio_sample_rate <= 10) return false;
252 have_video = 0, have_audio = 0;
254 raw_options_list = NULL;
257 memset(&video_st, 0x00, sizeof(video_st));
258 memset(&audio_st, 0x00, sizeof(audio_st));
260 /* Initialize libavcodec, and register all codecs and formats. */
261 #ifndef AVCODEC_UPPER_V56
267 do_clear_options_list();
268 do_add_option(QString::fromUtf8("c:v"), QString::fromUtf8("mpeg4"));
269 //do_add_option(QString::fromUtf8("c:a"), QString::fromUtf8("aac"));
270 //do_add_option(QString::fromUtf8("c:v"), QString::fromUtf8("theora"));
271 do_add_option(QString::fromUtf8("c:a"), QString::fromUtf8("vorbis"));
273 video_encode_threads = p_config->video_threads;
274 video_geometry = QSize(p_config->video_width, p_config->video_height);
275 audio_bit_rate = p_config->audio_bitrate * 1000;
279 for(int i = 0; i < encode_options.size(); i++) {
280 if(encode_opt_keys.size() <= i) break;
281 av_dict_set(&raw_options_list, encode_opt_keys.takeAt(i).toUtf8().constData(),
282 encode_options.takeAt(i).toUtf8().constData(), 0);
285 /* allocate the output media context */
286 avformat_alloc_output_context2(&oc, NULL, NULL, _filename.toLocal8Bit().constData());
288 // printf("Could not reduce output format from file extension: using MPEG.\n");
289 avformat_alloc_output_context2(&oc, NULL, "mpeg", _filename.toLocal8Bit().constData());
294 fmt = (AVOutputFormat *)(oc->oformat);
295 switch(p_config->video_codec_type) {
296 case VIDEO_CODEC_MPEG4:
297 fmt->video_codec = AV_CODEC_ID_MPEG4;
299 case VIDEO_CODEC_H264:
300 fmt->video_codec = AV_CODEC_ID_H264;
303 switch(p_config->audio_codec_type) {
304 case AUDIO_CODEC_MP3:
305 fmt->audio_codec = AV_CODEC_ID_MP3;
307 case AUDIO_CODEC_AAC:
308 fmt->audio_codec = AV_CODEC_ID_AAC;
310 case AUDIO_CODEC_VORBIS:
311 fmt->audio_codec = AV_CODEC_ID_VORBIS;
314 /* Add the audio and video streams using the default format codecs
315 * and initialize the codecs. */
316 if (fmt->video_codec != AV_CODEC_ID_NONE) {
318 if(!add_stream((void *)&video_st, (void *)oc, (void **)&video_codec, (uint64_t)fmt->video_codec)) goto _err_final;
322 if (fmt->audio_codec != AV_CODEC_ID_NONE) {
323 if(!add_stream((void *)&audio_st, (void *)oc, (void **)&audio_codec, (uint64_t)fmt->audio_codec)) goto _err_final;
329 /* Now that all the parameters are set, we can open the audio and
330 * video codecs and allocate the necessary encode buffers. */
337 av_dump_format(oc, 0, _filename.toLocal8Bit().constData(), 1);
339 /* open the output file, if needed */
340 if (!(fmt->flags & AVFMT_NOFILE)) {
341 ret = avio_open(&oc->pb, _filename.toLocal8Bit().constData(), AVIO_FLAG_WRITE);
343 out_debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER,
344 "Could not open '%s': %s\n", _filename.toLocal8Bit().constData(),
345 err2str(ret).toLocal8Bit().constData());
348 out_debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER,
349 "Success to Open file: '%s\n", _filename.toLocal8Bit().constData());
355 // audio_enqueue_count = 0;
357 /* Write the stream header, if any. */
358 ret = avformat_write_header(oc, &raw_options_list);
360 out_debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER,
361 "Error occurred when opening output file: %s\n",
362 err2str(ret).toLocal8Bit().constData());
365 emit sig_set_state_saving_movie(true);
368 avformat_free_context(oc);
370 output_context = NULL;
371 stream_format = NULL;
372 emit sig_set_state_saving_movie(false);
375 emit sig_set_state_saving_movie(true);
380 void MOVIE_SAVER::do_close()
386 void MOVIE_SAVER::do_close_main()
388 if(!req_close) return;
389 #if defined(USE_LIBAV)
390 if(output_context != NULL) {
391 AVFormatContext *oc = output_context;
392 AVOutputFormat *fmt = (AVOutputFormat *)(oc->oformat);
393 //AVPacket pkt = {0};
394 //AVCodecContext *c = video_st.st->codec;
396 //bool need_video_transcode, need_audio_transcode;
397 bool need_audio_transcode;
399 //need_video_transcode = need_audio_transcode = false;
400 need_audio_transcode = false;
401 /* Close each codec. */
402 //if(totalSrcFrame != totalDstFrame) {
403 while(!a_f || !v_f) {
404 if(audio_remain <= 0) {
405 a_f = audio_data_queue.isEmpty();
407 dequeue_audio(audio_frame_buf);
408 audio_remain = audio_size;
413 v_f = video_data_queue.isEmpty();
415 if(left_frames <= 0) dequeue_video(video_frame_buf);
417 video_remain = video_size;
422 #ifdef AVCODEC_UPPER_V56
423 if(audio_st.context != NULL) {
424 if(video_st.context != NULL) {
425 result = av_compare_ts(video_st.next_pts, video_st.context->time_base,
426 audio_st.next_pts, audio_st.context->time_base);
434 result = av_compare_ts(video_st.next_pts, video_st.st->codec->time_base,
435 audio_st.next_pts, audio_st.st->codec->time_base);
437 if ((n_encode_video == 0) &&
438 ((n_encode_audio != 0) || (result <= 0))) {
439 n_encode_video = write_video_frame();
440 if(n_encode_video < 0) break;
442 n_encode_audio = write_audio_frame();
443 if(n_encode_audio < 0) break;
447 close_stream(oc, &video_st);
450 close_stream(oc, &audio_st);
452 have_video = have_audio = 0;
454 av_write_trailer(oc);
456 if (!(fmt->flags & AVFMT_NOFILE))
457 avio_closep(&oc->pb);
459 /* free the stream */
460 avformat_free_context(output_context);
461 output_context = NULL;
462 stream_format = NULL;
463 audio_codec = video_codec = NULL;
464 raw_options_list = NULL;
466 memset(&video_st, 0x00, sizeof(video_st));
467 memset(&audio_st, 0x00, sizeof(audio_st));
469 if(raw_options_list != NULL) {
470 av_dict_free(&raw_options_list);
471 raw_options_list = NULL;
473 #endif // defined(USE_LIBAV)
474 memset(audio_frame_buf, 0x00, sizeof(audio_frame_buf));
475 memset(video_frame_buf, 0x00, sizeof(video_frame_buf));
477 uint64_t leftq_a, leftq_v;
478 leftq_a = leftq_v = 0;
479 while(!audio_data_queue.isEmpty()) {
480 QByteArray *pp = audio_data_queue.dequeue();
486 audio_data_queue.clear();
488 while(!video_data_queue.isEmpty()) {
489 VIDEO_DATA *pp = video_data_queue.dequeue();
491 if(pp->frames >= 0) leftq_v += pp->frames;
495 video_data_queue.clear();
497 out_debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_MOVIE_SAVER,
498 "Close: Left: Video %lld frames, Audio %lld frames",
503 out_debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_MOVIE_SAVER,
504 "MOVIE: Close: Write: Video %lld frames, Audio %lld frames", totalDstFrame, totalAudioFrame);
505 out_debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_MOVIE_SAVER,
506 "MOVIE: Close: Dequeue: Video %lld frames, Audio %lld frames", totalDstFrame, audio_count);
510 //audio_enqueue_count = 0;
514 audio_frame_offset = 0;
523 emit sig_set_state_saving_movie(false);
527 QString MOVIE_SAVER::create_date_file_name(void)
529 QDateTime nowTime = QDateTime::currentDateTime();
530 QString tmps = nowTime.toString(QString::fromUtf8("yyyy-MM-dd_hh-mm-ss.zzz."));