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 .
9 #include "movie_saver.h"
12 MOVIE_SAVER::MOVIE_SAVER(int width, int height, int fps, OSD *osd) : QThread(0)
14 buffer_size=8 * 1024 * 224;
17 bitrate = 2000 * 1000;
24 audio_data_queue.clear();
26 video_data_queue.clear();
27 video_width_queue.clear();
28 video_height_queue.clear();
36 MOVIE_SAVER::~MOVIE_SAVER()
41 void MOVIE_SAVER::enqueue_video(QByteArray *p, int width, int height)
43 if(!recording) return false;
45 QByteArray *pp = new QByteArray(p->data(), p->size());
47 video_data_queue.enqueue(pp);
48 video_width_queue.enqueue(width);
49 video_height_queue.enqueue(height);
52 bool MOVIE_SAVER::dequeue_video(uint32_t *p)
54 if(!recording) return false;
55 if(video_data_queue.isEmpty()) return false;
56 if(p == NULL) return false;
58 QByteArray *pp = video_data_queue.dequeue();
59 if((pp == NULL) || (video_size <= 0)) return false;
61 video_size = pp->size();
62 memcpy(p, pp->data(), video_size);
68 void MOVIE_SAVER::enqueue_audio(QByteArray *p)
70 if(!recording) return;
72 QByteArray *pp = new QByteArray(p->data(), p->size());
73 audio_data_queue.enqueue(pp);
76 bool MOVIE_SAVER::dequeue_audio(int16_t *p)
78 if(!recording) return false;
79 if(audio_data_queue.isEmpty()) return false;
80 if(p == NULL) return false;
82 QByteArray *pp = audio_data_queue.dequeue();
83 if((pp == NULL) || (audio_size <= 0)) return false;
85 audio_size = pp->size();
86 memcpy(p, pp->data(), audio_size);
91 void MOVIE_SAVER::run()
95 int fps_wait = (int)((1000.0 / this->vm_frame_rate()) / 2.0);
96 int tmp_wait = fps_wait;
99 if(!bRunThread) break;
100 if(!recording) break;
101 if(!audio_data_queue.isEmpty()) {
102 if(dequeue_audio(audio_frame)) {
104 uint64_t bytes = audio_size;
105 uint64_t us = (uint64_t)floor(((double)bytes * 1000000.0) / (double)audio_codec->sample_rate);
106 double samples = ((double)us / 1000000.0) * (double)audio_codec->sample_rate()
109 if(bytes == 0) goto _video;
111 av_init_packet(&pkt);
112 pkt.dts = pkt.pts = (int64_t)samples;
113 pkt.flags |= AV_PKT_FLAG_KEY;
114 pkt.data = (uint8_t *)audio_frame;
115 pkt.size = (uint32_t)bytes;
116 pkt.stream_index = 1;
117 ret = av_write_frame(output_context, &pkt);
124 if(!bRunThread) break;
125 if(!recording) break;
126 if(!video_data_queue.isEmpty() &&
127 !video_height_queue.isEmpty() && !video_width_queue.isEmpty()) {
129 if(dequeue_video(video_frame)) {
130 AVRational fps = {1, 1000000};
132 uint64_t bytes = video_size;
134 av_init_packet(&pkt);
145 if(fps_wait >= tmp_wait) {
146 this->msleep(tmp_wait);
149 this->msleep(fps_wait);
150 tmp_wait -= fps_wait;
153 fps_wait = (int)((1000.0 / this->vm_frame_rate()) / 2.0);
159 void MOVIE_SAVER::do_close()
161 if(output_context != NULL) {
162 av_write_trailer(output_context);
163 avio_close(output_context->pb);
165 if(audio_stream != NULL) {
166 av_free(audio_stream);
168 if(video_stream != NULL) {
169 av_free(video_stream);
174 if(output_context != NULL) {
175 av_free(output_context);
176 output_context = NULL;
180 audio_data_queue.clear();
182 video_data_queue.clear();
183 video_width_queue.clear();
184 video_height_queue.clear();
187 AGAR_DebugLog(AGAR_LOG_DEBUG, "MOVIE: Close: Read: Video %ll frames, Audio %ll frames", totalSrcFrame, totalAudioFrame);
188 AGAR_DebugLog(AGAR_LOG_DEBUG, "MOVIE: Close: Write: Video %ll frames, Audio %ll frames", totalDstFrame, totalAudioFrame);
194 QString MOVIE_PLAYER::create_date_file_name(void)
196 QDateTime nowTime = QDateTime::currentDateTime();
197 QString tmps = nowTime.toString(QString::fromUtf8("yyyy-MM-dd_hh-mm-ss.zzz."));
201 bool MOVIE_SAVER::is_recording(void)
205 static const AVRational time_base_15 = (AVRational){1001, 14485};
206 static const AVRational time_base_24 = (AVRational){1001, 23976};
207 static const AVRational time_base_25 = (AVRational){1001, 25025};
208 static const AVRational time_base_30 = (AVRational){1001, 29970};
209 static const AVRational time_base_60 = (AVRational){1001, 59940};
211 void MOVIE_SAVER::do_open(QString filename)
216 _filename = filename;
217 format = av_guess_format("mp4", NULL, NULL);
220 AGAR_DebugLog(AGAR_LOG_DEBUG, "AVC ERROR: Failed to initialize libavf");
224 output_context = avformat_alloc_context();
225 if(output_context == NULL) {
226 AGAR_DebugLog(AGAR_LOG_DEBUG, "AVC ERROR: Failed to get output_context");
231 output_context->oformat = format;
232 snprintf(output_context->filename, 1000, "file://%s", filename.fromUtf8().constData());
233 AGAR_DebugLog(AGAR_LOG_DEBUG, "Start rec VIDEO: %s", output_context->filename);
236 video_stream = av_new_stream(output_context, 0);
237 if(video_stream == NULL) {
238 AGAR_DebugLog(AGAR_LOG_DEBUG, "AVC ERROR: Failed to open video stream");
243 get_host_time(t_time);
244 video_codec = video_stream->codec;
245 video_codec->gop_size = 15;
246 video_codec->max_b_frames = 8;
247 video_codec->has_b_frames = 1;
248 QString author = QString::fromUtf8("emu");
249 author = author + osd->get_vm_config_name();
250 QString date_str = QString::fromUtf8("Record from");
251 date_str = date_str + create_date_file_name();
254 av_dict_set(&output_context->metadata, "title", date_str.fromUtf8().constData(), 0);
255 av_dict_set(&output_context->metadata, "author", author.fromUtf8().constData(), 0);
256 video_codec->has_b_frames=2; // let muxer know we may have bpyramid
257 video_codec->codec_id = CODEC_ID_H264;
258 video_codec->codec = &codec_real;
259 memset(video_codec->codec, 0, sizeof(struct AVCodec));
260 strcpy(video_codec->codec->name, "H264");
263 video_codec->rc_buffer_size = buffer_size;
264 video_codec->rc_max_rate = max_rate;
265 video_codec->rc_min_rate = min_rate;
266 video_codec->bit_rate = bitrate;
268 video_codec->codec_type = AVMEDIA_TYPE_VIDEO;
269 video_codec->flags = CODEC_FLAG_QSCALE;
270 video_codec->width = _width;
271 video_codec->height = _height;
276 video_codec->time_base = time_base_15;
277 video_codec->bit_rate = bitrate / 2;
278 video_codec->rc_max_rate = max_rate / 2;
279 video_codec->rc_min_rate = min_rate / 2;
282 video_codec->time_base = time_base_24;
285 video_codec->time_base = time_base_25;
288 video_codec->time_base = time_base_30;
291 video_codec->time_base = time_base_60;
292 video_codec->bit_rate = bitrate * 2;
293 video_codec->rc_max_rate = max_rate * 2;
294 video_codec->rc_min_rate = min_rate * 2;
297 time_base = (AVRational){1001, rec_fps * 1000};
298 video_codec->time_base = time_base;
299 video_codec->bit_rate = (int)((double)bitrate * 30.0 / (double)rec_fps);
300 video_codec->rc_max_rate = (int)((double)max_rate * 30.0 / (double)rec_fps);
301 video_codec->rc_min_rate = (int)((double)min_rate * 30.0 / (double)rec_fps);
306 //audio_stream = av_new_stream(output_context, 1);
307 audio_stream = av_new_stream(output_context, 0);
308 if(audio_stream == NULL) {
309 AGAR_DebugLog(AGAR_LOG_DEBUG, "AVC ERROR: Failed to open audio stream");
314 // Temporally using libAV's AAC
315 audio_codec = audio_stream->codec;
316 audio_codec->frame_size = 1024;
317 audio_codec->codec_id = CODEC_ID_AAC;
318 audio_codec->sample_rate = osd->get_sound_rate();
320 audio_codec->codec_type = AVMEDIA_TYPE_AUDIO;
322 audio_codec->bit_rate = audio_codec->sample_rate * 8 * 2;
323 audio_codec->rc_buffer_size = audio_codec->sample_rate / 4; // 250 ms worth
324 audio_codec->channels = 2;
327 output_context->mux_rate = 100080 * 1000;
328 output_context->pre_load = AV_TIME_BASE / 10;
329 output_context->max_delay = 100 * 1000; // MAX 100ms delay;
331 if(avio_open(&(output_context->pb), filename.fromUtf8().constData(), AVIO_FLAG_WRITE) < 0) {
332 AGAR_DebugLog(AGAR_LOG_DEBUG, "AVC ERROR: Failed to open file");
337 av_dump_format(output_context, 0, filename.fromUtf8().constData(), 1);
338 AGAR_DebugLog(AGAR_LOG_DEBUG, "Successfully opened AVC stream.");
343 void MOVIE_SAVER::do_exit()
348 void MOVIE_SAVER::do_set_record_fps(int fps)
350 if((fps > 0) && (fps <= 60)) rec_fps = fps;
353 void MOVIE_SAVER::do_set_width(int width)
358 void MOVIE_SAVER::do_set_height(int height)