OSDN Git Service

f5b8340f6da0bad0987da93d4884a5fa0641b363
[csp-qt/common_source_project-fm7.git] / source / src / qt / avio / movie_saver_video.cpp
1 /*
2  * Common Source Code Project for Qt : movie saver.
3  * (C) 2016 K.Ohta <whatisthis.sowhat _at_ gmail.com>
4  *  License: GPLv2
5  *  History: May 27, 2016 : Initial. This refer from avidemux 2.5.6 .
6  */
7
8 #include <QDateTime>
9 #include "common.h"
10 #include "movie_saver.h"
11 #include "../osd.h"
12 #include "csp_logger.h"
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <math.h>
18
19 #if defined(USE_LIBAV)
20 extern "C" {
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>
29 }
30         #if (LIBAVCODEC_VERSION_MAJOR > 56)
31         #define AVCODEC_UPPER_V56
32         #endif
33 #endif
34 /**************************************************************/
35 /* video output */
36
37 void MOVIE_SAVER::setup_h264(void *_codec_context)
38 {
39 #if defined(USE_LIBAV)
40         AVCodecContext *c = (AVCodecContext *)_codec_context;
41
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;
49         c->bidir_refine = 2;
50         c->refs = 5;
51         c->max_qdiff = 6;
52         c->me_subpel_quality = p_config->video_h264_subme;
53         c->i_quant_offset = 1.2;
54         c->i_quant_factor = 1.5;
55         c->trellis = 2;
56         c->mb_lmin = 4;
57         c->mb_lmax = 18;
58         c->bidir_refine = 2;
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. */
64         c->mb_decision = 2;
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);  
74 #else
75         c->scenechange_threshold = 40;
76         c->noise_reduction = 0;
77         c->chromaoffset = 2;
78         c->b_frame_strategy = p_config->video_h264_b_adapt;
79         c->b_sensitivity = 55;
80         c->me_method = ME_UMH;
81 #endif
82 #endif
83 }
84
85 void MOVIE_SAVER::setup_mpeg4(void *_codec)
86 {
87 #if defined(USE_LIBAV)  
88         AVCodecContext *c = (AVCodecContext *)_codec;
89         c->bidir_refine = 2;
90         c->refs = 5;
91         c->max_qdiff = 6;
92         c->i_quant_offset = 1.2;
93         c->i_quant_factor = 1.5;
94         c->trellis = 2;
95         c->mb_lmin = 4;
96         c->mb_lmax = 18;
97         c->bidir_refine = 2;
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) {
104                 int tmp;
105                 tmp = c->qmin;
106                 c->qmin = c->qmax;
107                 c->qmax = tmp;
108         }
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);
121 #else
122         c->scenechange_threshold = 30;
123         c->noise_reduction = 0;
124         c->chromaoffset = 2;
125         c->b_strategy = 1;
126         c->b_sensitivity = 55;
127 #endif
128 #endif
129 }
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)
132 {
133 #if defined(USE_LIBAV)
134         enum AVPixelFormat pix_fmt = (enum AVPixelFormat)_pix_fmt;
135         AVFrame *picture;
136         int ret;
137
138         picture = av_frame_alloc();
139         if (!picture)
140                 return (void *)NULL;
141
142         picture->format = pix_fmt;
143         picture->width  = width;
144         picture->height = height;
145
146         /* allocate the buffers for the frame data */
147         ret = av_frame_get_buffer(picture, 32);
148         if (ret < 0) {
149                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not allocate frame data.\n");
150                 return (void *)NULL;
151         }
152
153         return (void *)picture;
154 #else
155         return (void *)NULL;
156 #endif  
157 }
158
159 //void MOVIE_SAVER::open_video(OutputStream *_ost, AVDictionary *_opt_arg)
160 bool MOVIE_SAVER::open_video()
161 {
162 #if defined(USE_LIBAV)
163         int ret;
164         AVDictionary *opt_arg = raw_options_list;
165         OutputStream *ost = &video_st;
166         AVCodec *codec = video_codec;
167         AVCodecContext *c;
168         AVDictionary *opt = NULL;
169 #ifdef AVCODEC_UPPER_V56
170         c = ost->context;
171 #else
172         c = ost->st->codec;
173 #endif
174
175         av_dict_copy(&opt, opt_arg, 0);
176
177         /* open the codec */
178         ret = avcodec_open2(c, codec, &opt);
179         av_dict_free(&opt);
180         if (ret < 0) {
181                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not open video codec: %s\n", err2str(ret).toLocal8Bit().constData());
182                 return false;
183         }
184
185         /* allocate and init a re-usable frame */
186         ost->frame = (AVFrame *)alloc_picture(c->pix_fmt, c->width, c->height);
187         if (!ost->frame) {
188                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Could not allocate video frame\n");
189                 return false;
190         }
191
192         /* If the output format is not YUV420P, then a temporary YUV420P
193          * picture is needed too. It is then converted to the required
194          * output format. */
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");
201                 return false;
202         }
203         //}
204 #ifdef AVCODEC_UPPER_V56
205         ret = avcodec_parameters_from_context(ost->st->codecpar, c);
206         if (ret < 0) {
207                 fprintf(stderr, "Could not copy the stream parameters\n");
208                 return false;
209         }
210 #endif
211         p_logger->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_MOVIE_SAVER,
212                                                   "MOVIE: Open to write video : Success.");
213         return true;
214 #else
215         return false;
216 #endif
217 }
218
219
220 //static AVFrame *get_video_frame(OutputStream *ost)
221 void *MOVIE_SAVER::get_video_frame(void)
222 {
223 #if defined(USE_LIBAV)
224         OutputStream *ost = &video_st;
225         AVCodecContext *c;
226 #ifdef AVCODEC_UPPER_V56
227         c = ost->context;
228 #else
229         c = ost->st->codec;
230 #endif
231
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);
238                         ost->sws_ctx = NULL;
239                 }
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");
245                                 return (void *)NULL;
246                         }
247                 }
248         }
249         
250         old_height = _height;
251         old_width = _width;
252         
253         if (!ost->sws_ctx) {
254                 ost->sws_ctx = sws_getContext(ost->tmp_frame->width, ost->tmp_frame->height,
255                                                                           AV_PIX_FMT_RGBA,
256                                                                           c->width, c->height,
257                                                                           c->pix_fmt,
258                                                                           SCALE_FLAGS, NULL, NULL, NULL);
259                 if (!ost->sws_ctx) {
260                         p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER,
261                                         "Could not initialize the conversion context\n");
262                         return (void *)NULL;
263                 }
264         }
265         //const int in_linesize[1] = { 4 * _width };
266         //fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height);
267         {
268                 int w = _width;
269                 int h = _height;
270                 int x;
271                 int y;
272                 int yy[4];
273                 uint32_t *p;
274                 AVFrame *qq = ost->tmp_frame;
275                 uint32_t *q;
276                 uint32_t cacheline[8];
277                 //int ret;
278                 if(ost->tmp_frame != NULL) {
279                         //ret = av_frame_make_writable(ost->tmp_frame);
280                         av_frame_make_writable(ost->tmp_frame);
281                         //if (ret < 0)
282                         //exit(1);
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++) {
288                                         cacheline[0] = p[0];
289                                         cacheline[1] = p[1];
290                                         cacheline[2] = p[2];
291                                         cacheline[3] = p[3];
292                                         cacheline[4] = p[4];
293                                         cacheline[5] = p[5];
294                                         cacheline[6] = p[6];
295                                         cacheline[7] = p[7];
296
297                                         q[0] = cacheline[0];
298                                         q[1] = cacheline[1];
299                                         q[2] = cacheline[2];
300                                         q[3] = cacheline[3];
301                                         q[4] = cacheline[4];
302                                         q[5] = cacheline[5];
303                                         q[6] = cacheline[6];
304                                         q[7] = cacheline[7];
305
306                                         q += 8;
307                                         p += 8;
308                                 }
309                                 if((w & 7) != 0) {
310                                         for(x = 0; x < (w & 7); x++) {
311                                                 q[x] = p[x];
312                                         }
313                                 }
314                         }
315                 }
316                 sws_scale(ost->sws_ctx,
317                                   ost->tmp_frame->data, ost->tmp_frame->linesize,
318                                   0, _height, ost->frame->data, ost->frame->linesize);
319         }
320         ost->frame->pts = ost->next_pts++;
321         return (void *)(ost->frame);
322 #else
323         return (void *)NULL;
324 #endif  
325 }
326
327 /*
328  * encode one video frame and send it to the muxer
329  * return 1 when encoding is finished, 0 otherwise
330  */
331 //static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
332 int MOVIE_SAVER::write_video_frame()
333 {
334 #if defined(USE_LIBAV)
335         int ret;
336         AVFormatContext *oc = output_context;
337         OutputStream *ost = &video_st;
338         AVCodecContext *c;
339         AVFrame *frame;
340         int got_packet = 0;
341         AVPacket pkt = { 0 };
342
343 #ifdef AVCODEC_UPPER_V56
344         c = ost->context;
345 #else
346         c = ost->st->codec;
347 #endif
348
349         frame = (AVFrame *)get_video_frame();
350         av_init_packet(&pkt);
351         /* encode the image */
352         frame->pts = totalDstFrame;
353         //got_packet = 1;
354         //while(got_packet) {
355 #ifdef AVCODEC_UPPER_V56
356         if(frame != NULL) {
357                 ret = avcodec_send_frame(c, frame);
358                 if(ret < 0) {
359                         return -1;
360                         if(ret == AVERROR_EOF) {        
361                                 return 1;
362                                 //return 0;
363                         }
364                         return ((ret == AVERROR(EAGAIN)) ? 0 : -1);
365                 }
366                 totalDstFrame++;
367                 while (ret  >= 0) {
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());
374                                 return -1;
375                         }
376                         pkt.stream_index = 0;
377                         int ret2 = this->write_frame((void *)oc, (const void *)&c->time_base, (void *)ost->st, (void *)&pkt);
378                         if (ret2 < 0) {
379                                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Error while writing video frame: %s\n", err2str(ret2).toLocal8Bit().constData());
380                                 return -1;
381                         }
382                         got_packet = 1;
383                         av_packet_unref(&pkt);
384                 }
385         }
386         return (frame || got_packet) ? 0 : 1;
387 #else
388         ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
389         if (ret < 0) {
390                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Error encoding video frame: %s\n", err2str(ret).toLocal8Bit().constData());
391                 return -1;
392         }
393         //if(!got_packet) break;
394         totalDstFrame++;
395         if (got_packet) {
396                 ret = this->write_frame((void *)oc, (const void *)&c->time_base, (void *)ost->st, (void *)&pkt);
397                 
398                 // ret = write_frame(oc, &c->time_base, ost->st, &pkt);
399         } else {
400                 ret = 0;
401         }
402         if (ret < 0) {
403                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_MOVIE_SAVER, "Error while writing video frame: %s\n", err2str(ret).toLocal8Bit().constData());
404                 return -1;
405         }
406         
407         //}
408         //if(frame) {
409         //      char buf[256];
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);
413         //}
414         return (frame || got_packet) ? 0 : 1;
415 #endif
416 #else
417         return 1;
418 #endif
419 }