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 "movie_saver.h"
12 #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
34 /**************************************************************/
37 void MOVIE_SAVER::setup_h264(void *_codec_context)
39 #if defined(USE_LIBAV)
40 AVCodecContext *c = (AVCodecContext *)_codec_context;
42 c->qmin = p_config->video_h264_minq;
43 c->qmax = p_config->video_h264_maxq;
44 c->bit_rate = p_config->video_h264_bitrate * 1000;
45 c->max_b_frames = p_config->video_h264_bframes;
46 c->b_quant_offset = 2;
47 c->temporal_cplx_masking = 0.1;
48 c->spatial_cplx_masking = 0.15;
52 c->me_subpel_quality = p_config->video_h264_subme;
53 c->i_quant_offset = 1.2;
54 c->i_quant_factor = 1.5;
59 c->keyint_min = rec_fps / 5;
60 c->gop_size = rec_fps * 5;
61 /* Needed to avoid using macroblocks in which some coeffs overflow.
62 * This does not happen with normal video, it just happens here as
63 * the motion of the chroma plane does not match the luma plane. */
65 c->profile=FF_PROFILE_H264_HIGH;
66 #ifdef AVCODEC_UPPER_V56
67 av_dict_set(&raw_options_list, _T("me_method"), _T("umh"), 0);
68 av_dict_set_int(&raw_options_list, _T("qmin"), p_config->video_h264_minq, 0);
69 av_dict_set_int(&raw_options_list, _T("qmax"), p_config->video_h264_maxq, 0);
70 av_dict_set_int(&raw_options_list, _T("sc_threshold"), 40, 0);
71 av_dict_set_int(&raw_options_list, _T("noise_reduction"), 0, 0);
72 av_dict_set_int(&raw_options_list, _T("chromaoffset"), 2, 0);
73 av_dict_set_int(&raw_options_list, _T("b_strategy"), p_config->video_h264_b_adapt, 0);
75 c->scenechange_threshold = 40;
76 c->noise_reduction = 0;
78 c->b_frame_strategy = p_config->video_h264_b_adapt;
79 c->b_sensitivity = 55;
80 c->me_method = ME_UMH;
85 void MOVIE_SAVER::setup_mpeg4(void *_codec)
87 #if defined(USE_LIBAV)
88 AVCodecContext *c = (AVCodecContext *)_codec;
92 c->i_quant_offset = 1.2;
93 c->i_quant_factor = 1.5;
98 c->keyint_min = rec_fps / 5;
99 c->gop_size = rec_fps * 5;
100 c->gop_size = rec_fps; /* emit one intra frame every one second */
101 c->qmin = p_config->video_mpeg4_minq;
102 c->qmax = p_config->video_mpeg4_maxq;
103 if(c->qmin > c->qmax) {
109 if(c->qmin <= 0) c->qmin = 1;
110 if(c->qmax <= 0) c->qmax = 1;
111 c->max_b_frames = p_config->video_mpeg4_bframes;
112 c->bit_rate = p_config->video_mpeg4_bitrate * 1000;
113 c->b_quant_offset = 2;
114 c->temporal_cplx_masking = 0.1;
115 c->spatial_cplx_masking = 0.15;
116 #ifdef AVCODEC_UPPER_V56
117 av_dict_set_int(&raw_options_list, _T("sc_threshold"), 30, 0);
118 av_dict_set_int(&raw_options_list, _T("quantizer_noise_shaping"), 0, 0);
119 av_dict_set_int(&raw_options_list, _T("b_strategy"), 1, 0);
120 av_dict_set_int(&raw_options_list, _T("b_sensitivity"), 55, 0);
122 c->scenechange_threshold = 30;
123 c->noise_reduction = 0;
126 c->b_sensitivity = 55;
130 //static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
131 void *MOVIE_SAVER::alloc_picture(uint64_t _pix_fmt, int width, int height)
133 #if defined(USE_LIBAV)
134 enum AVPixelFormat pix_fmt = (enum AVPixelFormat)_pix_fmt;
138 picture = av_frame_alloc();
142 picture->format = pix_fmt;
143 picture->width = width;
144 picture->height = height;
146 /* allocate the buffers for the frame data */
147 ret = av_frame_get_buffer(picture, 32);
149 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not allocate frame data.\n");
153 return (void *)picture;
159 //void MOVIE_SAVER::open_video(OutputStream *_ost, AVDictionary *_opt_arg)
160 bool MOVIE_SAVER::open_video()
162 #if defined(USE_LIBAV)
164 AVDictionary *opt_arg = raw_options_list;
165 OutputStream *ost = &video_st;
166 AVCodec *codec = video_codec;
168 AVDictionary *opt = NULL;
169 #ifdef AVCODEC_UPPER_V56
175 av_dict_copy(&opt, opt_arg, 0);
178 ret = avcodec_open2(c, codec, &opt);
181 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not open video codec: %s\n", err2str(ret).toLocal8Bit().constData());
185 /* allocate and init a re-usable frame */
186 ost->frame = (AVFrame *)alloc_picture(c->pix_fmt, c->width, c->height);
188 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not allocate video frame\n");
192 /* If the output format is not YUV420P, then a temporary YUV420P
193 * picture is needed too. It is then converted to the required
195 ost->tmp_frame = NULL;
196 old_width = old_height = -1;
197 //if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
198 ost->tmp_frame = (AVFrame *)alloc_picture(AV_PIX_FMT_RGBA, _width, _height);
199 if (!ost->tmp_frame) {
200 fprintf(stderr, "Could not allocate temporary picture\n");
204 #ifdef AVCODEC_UPPER_V56
205 ret = avcodec_parameters_from_context(ost->st->codecpar, c);
207 fprintf(stderr, "Could not copy the stream parameters\n");
211 p_logger->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_MOVIE_SAVER,
212 "MOVIE: Open to write video : Success.");
220 //static AVFrame *get_video_frame(OutputStream *ost)
221 void *MOVIE_SAVER::get_video_frame(void)
223 #if defined(USE_LIBAV)
224 OutputStream *ost = &video_st;
226 #ifdef AVCODEC_UPPER_V56
232 //if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
233 /* as we only generate a YUV420P picture, we must convert it
234 * to the codec pixel format if needed */
235 if((old_width != _width) || (old_height != _height)) {
236 if(ost->sws_ctx != NULL) {
237 sws_freeContext(ost->sws_ctx);
240 if(ost->tmp_frame != NULL) {
241 av_frame_free(&ost->tmp_frame);
242 ost->tmp_frame = (AVFrame *)alloc_picture(AV_PIX_FMT_RGBA, _width, _height);
243 if (ost->tmp_frame == NULL) {
244 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not re-allocate video frame\n");
250 old_height = _height;
254 ost->sws_ctx = sws_getContext(ost->tmp_frame->width, ost->tmp_frame->height,
258 SCALE_FLAGS, NULL, NULL, NULL);
260 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER,
261 "Could not initialize the conversion context\n");
265 //const int in_linesize[1] = { 4 * _width };
266 //fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height);
274 AVFrame *qq = ost->tmp_frame;
276 uint32_t cacheline[8];
278 if(ost->tmp_frame != NULL) {
279 //ret = av_frame_make_writable(ost->tmp_frame);
280 av_frame_make_writable(ost->tmp_frame);
283 for(y = 0; y < h; y++) {
284 yy[0] = y * qq->linesize[0];
285 p = (uint32_t *)(&(video_frame_buf[y * w]));
286 q = (uint32_t *)(&(qq->data[0][yy[0]]));
287 for(x = 0; x < (w / 8); x++) {
310 for(x = 0; x < (w & 7); x++) {
316 sws_scale(ost->sws_ctx,
317 ost->tmp_frame->data, ost->tmp_frame->linesize,
318 0, _height, ost->frame->data, ost->frame->linesize);
320 ost->frame->pts = ost->next_pts++;
321 return (void *)(ost->frame);
328 * encode one video frame and send it to the muxer
329 * return 1 when encoding is finished, 0 otherwise
331 //static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
332 int MOVIE_SAVER::write_video_frame()
334 #if defined(USE_LIBAV)
336 AVFormatContext *oc = output_context;
337 OutputStream *ost = &video_st;
341 AVPacket pkt = { 0 };
343 #ifdef AVCODEC_UPPER_V56
349 frame = (AVFrame *)get_video_frame();
350 av_init_packet(&pkt);
351 /* encode the image */
352 frame->pts = totalDstFrame;
354 //while(got_packet) {
355 #ifdef AVCODEC_UPPER_V56
357 ret = avcodec_send_frame(c, frame);
360 if(ret == AVERROR_EOF) {
364 return ((ret == AVERROR(EAGAIN)) ? 0 : -1);
368 ret = avcodec_receive_packet(c, &pkt);
369 if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
370 return (frame || got_packet) ? 0 : 1;
371 } else if (ret < 0) {
372 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Error while writing video frame: %s\n",
373 err2str(ret).toLocal8Bit().constData());
376 pkt.stream_index = 0;
377 int ret2 = this->write_frame((void *)oc, (const void *)&c->time_base, (void *)ost->st, (void *)&pkt);
379 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Error while writing video frame: %s\n", err2str(ret2).toLocal8Bit().constData());
383 av_packet_unref(&pkt);
386 return (frame || got_packet) ? 0 : 1;
388 ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
390 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Error encoding video frame: %s\n", err2str(ret).toLocal8Bit().constData());
393 //if(!got_packet) break;
396 ret = this->write_frame((void *)oc, (const void *)&c->time_base, (void *)ost->st, (void *)&pkt);
398 // ret = write_frame(oc, &c->time_base, ost->st, &pkt);
403 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Error while writing video frame: %s\n", err2str(ret).toLocal8Bit().constData());
410 // memset(buf, 0x00, sizeof(buf));
411 // char *s = av_ts_make_time_string(buf, frame->pts, &c->time_base);
412 // AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie: Write video to file. sec=%s", s);
414 return (frame || got_packet) ? 0 : 1;