MythTV  master
avformatwriter.cpp
Go to the documentation of this file.
1 /* -*- Mode: c++ -*-
2  *
3  * Class AVFormatWriter
4  *
5  * Copyright (C) Chris Pinkham 2011
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "mythlogging.h"
23 #include "mythcorecontext.h"
24 #include "avformatwriter.h"
25 #include "audiooutpututil.h"
26 #include "mythavutil.h"
27 
28 extern "C" {
29 #if HAVE_BIGENDIAN
30 #include "bswap.h"
31 #endif
32 #include "libavutil/opt.h"
33 #include "libavutil/samplefmt.h"
34 #include "libavutil/imgutils.h"
35 }
36 
37 #define LOC QString("AVFW(%1): ").arg(m_filename)
38 #define LOC_ERR QString("AVFW(%1) Error: ").arg(m_filename)
39 #define LOC_WARN QString("AVFW(%1) Warning: ").arg(m_filename)
40 
42  : FileWriterBase(),
43 
44  m_avfRingBuffer(nullptr), m_ringBuffer(nullptr),
45  m_ctx(nullptr),
46  m_videoStream(nullptr), m_avVideoCodec(nullptr),
47  m_audioStream(nullptr), m_avAudioCodec(nullptr),
48  m_picture(nullptr),
49  m_audPicture(nullptr),
50  m_audioInBuf(nullptr), m_audioInPBuf(nullptr)
51 {
52  memset(&m_fmt, 0, sizeof(m_fmt));
53 }
54 
56 {
57  QMutexLocker locker(avcodeclock);
58 
59  if (m_ctx)
60  {
61  (void)av_write_trailer(m_ctx);
62  avio_closep(&m_ctx->pb);
63  for(unsigned int i = 0; i < m_ctx->nb_streams; i++) {
64  av_freep(&m_ctx->streams[i]);
65  }
66  av_freep(&m_ctx);
67  }
68 
69  if (m_audioInBuf)
70  av_freep(&m_audioInBuf);
71 
72  if (m_audioInPBuf)
73  av_freep(&m_audioInPBuf);
74 
75  if (m_audPicture)
76  av_frame_free(&m_audPicture);
77 
78  Cleanup();
79 
80  av_frame_free(&m_picture);
81 }
82 
84 {
85  AVOutputFormat *fmt = av_guess_format(m_container.toLatin1().constData(),
86  nullptr, nullptr);
87  if (!fmt)
88  {
89  LOG(VB_RECORD, LOG_ERR, LOC +
90  QString("Init(): Unable to guess AVOutputFormat from container %1")
91  .arg(m_container));
92  return false;
93  }
94 
95  m_fmt = *fmt;
96 
97  if (m_width && m_height)
98  {
99  m_avVideoCodec = avcodec_find_encoder_by_name(
100  m_videoCodec.toLatin1().constData());
101  if (!m_avVideoCodec)
102  {
103  LOG(VB_RECORD, LOG_ERR, LOC +
104  QString("Init(): Unable to find video codec %1").arg(m_videoCodec));
105  return false;
106  }
107 
108  m_fmt.video_codec = m_avVideoCodec->id;
109  }
110  else
111  m_fmt.video_codec = AV_CODEC_ID_NONE;
112 
113  m_avAudioCodec = avcodec_find_encoder_by_name(
114  m_audioCodec.toLatin1().constData());
115  if (!m_avAudioCodec)
116  {
117  LOG(VB_RECORD, LOG_ERR, LOC +
118  QString("Init(): Unable to find audio codec %1").arg(m_audioCodec));
119  return false;
120  }
121 
122  m_fmt.audio_codec = m_avAudioCodec->id;
123 
124  m_ctx = avformat_alloc_context();
125  if (!m_ctx)
126  {
127  LOG(VB_RECORD, LOG_ERR,
128  LOC + "Init(): Unable to allocate AVFormatContext");
129  return false;
130  }
131 
132  m_ctx->oformat = &m_fmt;
133 
134  if (m_container == "mpegts")
135  m_ctx->packet_size = 2324;
136 
137  snprintf(m_ctx->filename, sizeof(m_ctx->filename), "%s",
138  m_filename.toLatin1().constData());
139 
140  if (m_fmt.video_codec != AV_CODEC_ID_NONE)
142  if (m_fmt.audio_codec != AV_CODEC_ID_NONE)
144 
145  if ((m_videoStream) && (!OpenVideo()))
146  {
147  LOG(VB_RECORD, LOG_ERR, LOC + "Init(): OpenVideo() failed");
148  return false;
149  }
150 
151  if ((m_audioStream) && (!OpenAudio()))
152  {
153  LOG(VB_RECORD, LOG_ERR, LOC + "Init(): OpenAudio() failed");
154  return false;
155  }
156 
157  return true;
158 }
159 
161 {
162  if (!(m_fmt.flags & AVFMT_NOFILE))
163  {
164  if (avio_open(&m_ctx->pb, m_filename.toLatin1().constData(),
165  AVIO_FLAG_WRITE) < 0)
166  {
167  LOG(VB_RECORD, LOG_ERR, LOC + "OpenFile(): avio_open() failed");
168  return false;
169  }
170  }
171 
173 
174  if (!m_ringBuffer || !m_ringBuffer->GetLastError().isEmpty())
175  {
176  LOG(VB_RECORD, LOG_ERR, LOC +
177  QString("OpenFile(): RingBuffer::Create() failed: '%1'")
178  .arg(m_ringBuffer ? m_ringBuffer->GetLastError() : ""));
179  Cleanup();
180  return false;
181  }
182 
184  URLContext *uc = (URLContext *)m_ctx->pb->opaque;
186  uc->priv_data = (void *)m_avfRingBuffer;
187 
188  if (avformat_write_header(m_ctx, nullptr) < 0)
189  {
190  Cleanup();
191  return false;
192  }
193 
194  return true;
195 }
196 
198 {
199  if (m_ctx && m_ctx->pb)
200  {
201  avio_closep(&m_ctx->pb);
202  }
203  delete m_avfRingBuffer;
204  m_avfRingBuffer = nullptr;
205  delete m_ringBuffer;
206  m_ringBuffer = nullptr;
207 }
208 
210 {
211  if (m_ctx)
212  {
213  (void)av_write_trailer(m_ctx);
214  avio_close(m_ctx->pb);
215  for(unsigned int i = 0; i < m_ctx->nb_streams; i++) {
216  av_freep(&m_ctx->streams[i]);
217  }
218 
219  av_freep(&m_ctx);
220  }
221 
222  return true;
223 }
224 
226 {
227  if ((m_bufferedVideoFrameTypes.isEmpty()) ||
228  (m_bufferedVideoFrameTypes.first() == AV_PICTURE_TYPE_I))
229  return true;
230 
231  return false;
232 }
233 
235 {
236  int framesEncoded = m_framesWritten + m_bufferedVideoFrameTimes.size();
237 
238  av_frame_unref(m_picture);
239  AVPictureFill(m_picture, frame);
240  m_picture->pts = framesEncoded + 1;
241 
242  if ((framesEncoded % m_keyFrameDist) == 0)
243  m_picture->pict_type = AV_PICTURE_TYPE_I;
244  else
245  m_picture->pict_type = AV_PICTURE_TYPE_NONE;
246 
247  int got_pkt = 0;
248  int ret = 0;
249 
250  m_bufferedVideoFrameTimes.push_back(frame->timecode);
251  m_bufferedVideoFrameTypes.push_back(m_picture->pict_type);
252 
253  AVPacket pkt;
254  av_init_packet(&pkt);
255  pkt.data = nullptr;
256  pkt.size = 0;
257  AVCodecContext *avctx = gCodecMap->getCodecContext(m_videoStream);
258  {
259  QMutexLocker locker(avcodeclock);
260  ret = avcodec_encode_video2(avctx, &pkt,
261  m_picture, &got_pkt);
262  }
263 
264  if (ret < 0)
265  {
266  LOG(VB_RECORD, LOG_ERR, "avcodec_encode_video2() failed");
267  return ret;
268  }
269 
270  if (!got_pkt)
271  {
272  //LOG(VB_RECORD, LOG_DEBUG, QString("WriteVideoFrame(): Frame Buffered: cs: %1, mfw: %2, f->tc: %3, fn: %4, pt: %5").arg(pkt.size).arg(m_framesWritten).arg(frame->timecode).arg(frame->frameNumber).arg(m_picture->pict_type));
273  return ret;
274  }
275 
276  long long tc = frame->timecode;
277 
278  if (!m_bufferedVideoFrameTimes.isEmpty())
279  tc = m_bufferedVideoFrameTimes.takeFirst();
280  if (!m_bufferedVideoFrameTypes.isEmpty())
281  {
282  int pict_type = m_bufferedVideoFrameTypes.takeFirst();
283  if (pict_type == AV_PICTURE_TYPE_I)
284  pkt.flags |= AV_PKT_FLAG_KEY;
285  }
286 
287  if (m_startingTimecodeOffset == -1)
288  m_startingTimecodeOffset = tc - 1;
290 
291  pkt.pts = tc * m_videoStream->time_base.den / m_videoStream->time_base.num / 1000;
292  pkt.dts = AV_NOPTS_VALUE;
293  pkt.stream_index= m_videoStream->index;
294 
295  //LOG(VB_RECORD, LOG_DEBUG, QString("WriteVideoFrame(): cs: %1, mfw: %2, pkt->pts: %3, tc: %4, fn: %5, pic->pts: %6, f->tc: %7, pt: %8").arg(pkt.size).arg(m_framesWritten).arg(pkt.pts).arg(tc).arg(frame->frameNumber).arg(m_picture->pts).arg(frame->timecode).arg(m_picture->pict_type));
296  ret = av_interleaved_write_frame(m_ctx, &pkt);
297  if (ret != 0)
298  LOG(VB_RECORD, LOG_ERR, LOC + "WriteVideoFrame(): "
299  "av_interleaved_write_frame couldn't write Video");
300 
301  frame->timecode = tc + m_startingTimecodeOffset;
302  m_framesWritten++;
303 
304  av_packet_unref(&pkt);
305 
306  return 1;
307 }
308 
309 #if HAVE_BIGENDIAN
310 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
311  __attribute__ ((unused)); /* <- suppress compiler warning */
312 
313 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
314 {
315  for (int i = 0; i < audio_channels * buf_cnt; i++)
316  buf[i] = bswap_16(buf[i]);
317 }
318 #endif
319 
320 int AVFormatWriter::WriteAudioFrame(unsigned char *buf, int /*fnum*/, long long &timecode)
321 {
322 #if HAVE_BIGENDIAN
323  bswap_16_buf((short int*) buf, m_audioFrameSize, m_audioChannels);
324 #endif
325 
326  bool got_packet = false;
327  int ret = 0;
328  AVCodecContext *avctx = gCodecMap->getCodecContext(m_audioStream);
329  int samples_per_avframe = m_audioFrameSize * m_audioChannels;
330  int sampleSizeIn = AudioOutputSettings::SampleSize(FORMAT_S16);
331  AudioFormat format =
333  int sampleSizeOut = AudioOutputSettings::SampleSize(format);
334 
335  AVPacket pkt;
336  av_init_packet(&pkt);
337  pkt.data = nullptr;
338  pkt.size = 0;
339 
340  if (av_get_packed_sample_fmt(avctx->sample_fmt) == AV_SAMPLE_FMT_FLT)
341  {
342  AudioOutputUtil::toFloat(FORMAT_S16, (void *)m_audioInBuf, (void *)buf,
343  samples_per_avframe * sampleSizeIn);
344  buf = m_audioInBuf;
345  }
346  if (av_sample_fmt_is_planar(avctx->sample_fmt))
347  {
351  buf,
352  samples_per_avframe * sampleSizeOut);
353 
354  // init AVFrame for planar data (input is interleaved)
355  for (int j = 0, jj = 0; j < m_audioChannels; j++, jj += m_audioFrameSize)
356  {
357  m_audPicture->data[j] = m_audioInPBuf + jj * sampleSizeOut;
358  }
359  }
360  else
361  {
362  m_audPicture->data[0] = buf;
363  }
364 
365  m_audPicture->linesize[0] = m_audioFrameSize;
366  m_audPicture->nb_samples = m_audioFrameSize;
367  m_audPicture->format = avctx->sample_fmt;
368  m_audPicture->extended_data = m_audPicture->data;
369 
370  m_bufferedAudioFrameTimes.push_back(timecode);
371 
372  {
373  QMutexLocker locker(avcodeclock);
374  // SUGGESTION
375  // Now that avcodec_encode_audio2 is deprecated and replaced
376  // by 2 calls, this could be optimized
377  // into separate routines or separate threads.
378  got_packet = false;
379  ret = avcodec_receive_packet(avctx, &pkt);
380  if (ret == 0)
381  got_packet = true;
382  if (ret == AVERROR(EAGAIN))
383  ret = 0;
384  if (ret == 0)
385  ret = avcodec_send_frame(avctx, m_audPicture);
386  // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
387  // there are 2 packets to be received while only 1 frame to be
388  // sent. The code does not cater for this. Hopefully it will not happen.
389  }
390 
391  if (ret < 0)
392  {
393  char error[AV_ERROR_MAX_STRING_SIZE];
394  LOG(VB_GENERAL, LOG_ERR, LOC +
395  QString("audio encode error: %1 (%2)")
396  .arg(av_make_error_string(error, sizeof(error), ret))
397  .arg(got_packet));
398  return ret;
399  }
400 
401  if (!got_packet)
402  {
403  //LOG(VB_RECORD, LOG_ERR, QString("WriteAudioFrame(): Frame Buffered: cs: %1, mfw: %2, f->tc: %3, fn: %4").arg(m_audPkt->size).arg(m_framesWritten).arg(timecode).arg(fnum));
404  return ret;
405  }
406 
407  long long tc = timecode;
408 
409  if (m_bufferedAudioFrameTimes.size())
410  tc = m_bufferedAudioFrameTimes.takeFirst();
411 
412  if (m_startingTimecodeOffset == -1)
413  m_startingTimecodeOffset = tc - 1;
415 
416  if (m_avVideoCodec)
417  pkt.pts = tc * m_videoStream->time_base.den / m_videoStream->time_base.num / 1000;
418  else
419  pkt.pts = tc * m_audioStream->time_base.den / m_audioStream->time_base.num / 1000;
420 
421  pkt.dts = AV_NOPTS_VALUE;
422  pkt.flags |= AV_PKT_FLAG_KEY;
423  pkt.stream_index = m_audioStream->index;
424 
425  //LOG(VB_RECORD, LOG_ERR, QString("WriteAudioFrame(): cs: %1, mfw: %2, pkt->pts: %3, tc: %4, fn: %5, f->tc: %6").arg(m_audPkt->size).arg(m_framesWritten).arg(m_audPkt->pts).arg(tc).arg(fnum).arg(timecode));
426 
427  ret = av_interleaved_write_frame(m_ctx, &pkt);
428  if (ret != 0)
429  LOG(VB_RECORD, LOG_ERR, LOC + "WriteAudioFrame(): "
430  "av_interleaved_write_frame couldn't write Audio");
431  timecode = tc + m_startingTimecodeOffset;
432 
433  av_packet_unref(&pkt);
434 
435  return 1;
436 }
437 
438 int AVFormatWriter::WriteTextFrame(int /*vbimode*/, unsigned char */*buf*/, int /*len*/,
439  long long /*timecode*/, int /*pagenr*/)
440 {
441  return 1;
442 }
443 
444 bool AVFormatWriter::ReOpen(QString filename)
445 {
446  bool result = m_ringBuffer->ReOpen(filename);
447 
448  if (result)
449  m_filename = filename;
450 
451  return result;
452 }
453 
455 {
456  AVCodecContext *c;
457  AVStream *st;
458  AVCodec *codec;
459 
460  st = avformat_new_stream(m_ctx, nullptr);
461  if (!st)
462  {
463  LOG(VB_RECORD, LOG_ERR,
464  LOC + "AddVideoStream(): avformat_new_stream() failed");
465  return nullptr;
466  }
467  st->id = 0;
468 
469 
470  codec = avcodec_find_encoder(m_ctx->oformat->video_codec);
471  if (!codec)
472  {
473  LOG(VB_RECORD, LOG_ERR,
474  LOC + "AddVideoStream(): avcodec_find_encoder() failed");
475  return nullptr;
476  }
477 
479  c = gCodecMap->getCodecContext(st, codec);
480 
481  c->codec = codec;
482  c->codec_id = m_ctx->oformat->video_codec;
483  c->codec_type = AVMEDIA_TYPE_VIDEO;
484 
485  c->bit_rate = m_videoBitrate;
486  c->width = m_width;
487  c->height = m_height;
488 
489  // c->sample_aspect_ratio.num = (int)floor(m_aspect * 10000);
490  // c->sample_aspect_ratio.den = 10000;
491 
492  c->time_base = GetCodecTimeBase();
493 
494  st->time_base.den = 90000;
495  st->time_base.num = 1;
496  st->r_frame_rate.num = 0;
497  st->r_frame_rate.den = 0;
498 
499  c->gop_size = m_keyFrameDist;
500  c->pix_fmt = AV_PIX_FMT_YUV420P;
501  c->thread_count = m_encodingThreadCount;
502  c->thread_type = FF_THREAD_SLICE;
503 
504  if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
505  c->max_b_frames = 2;
506  }
507  else if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO)
508  {
509  c->mb_decision = 2;
510  }
511  else if (c->codec_id == AV_CODEC_ID_H264)
512  {
513 
514  // Try to provide the widest software/device support by automatically using
515  // the Baseline profile where the given bitrate and resolution permits
516 
517  if ((c->height > 720) || // Approximate highest resolution supported by Baseline 3.1
518  (c->bit_rate > 1000000)) // 14,000 Kbps aka 14Mbps maximum permissable rate for Baseline 3.1
519  {
520  c->level = 40;
521  // AVCodecContext AVOptions:
522  av_opt_set(c->priv_data, "profile", "main", 0);
523  }
524  else if ((c->height > 576) || // Approximate highest resolution supported by Baseline 3.0
525  (c->bit_rate > 1000000)) // 10,000 Kbps aka 10Mbps maximum permissable rate for Baseline 3.0
526  {
527  c->level = 31;
528  // AVCodecContext AVOptions:
529  av_opt_set(c->priv_data, "profile", "baseline", 0);
530  }
531  else
532  {
533  c->level = 30; // Baseline 3.0 is the most widely supported, but it's limited to SD
534  // AVCodecContext AVOptions:
535  av_opt_set(c->priv_data, "profile", "baseline", 0);
536  }
537 
538  // AVCodecContext AVOptions:
539  // c->coder_type = 0;
540  av_opt_set_int(c, "coder", FF_CODER_TYPE_VLC, 0);
541  c->max_b_frames = 0;
542  c->slices = 8;
543 
544  c->flags |= AV_CODEC_FLAG_LOOP_FILTER;
545  c->me_cmp |= 1;
546  // c->me_method = ME_HEX;
547  // av_opt_set_int(c, "me_method", ME_HEX, 0);
548  av_opt_set(c, "me_method", "hex", 0);
549  c->me_subpel_quality = 6;
550  c->me_range = 16;
551  c->keyint_min = 25;
552  // c->scenechange_threshold = 40;
553  av_opt_set_int(c, "sc_threshold", 40, 0);
554  c->i_quant_factor = 0.71;
555  // c->b_frame_strategy = 1;
556  av_opt_set_int(c, "b_strategy", 1, 0);
557  c->qcompress = 0.6;
558  c->qmin = 10;
559  c->qmax = 51;
560  c->max_qdiff = 4;
561  c->refs = 3;
562  c->trellis = 0;
563 
564  // libx264 AVOptions:
565  av_opt_set(c, "partitions", "i8x8,i4x4,p8x8,b8x8", 0);
566  av_opt_set_int(c, "direct-pred", 1, 0);
567  av_opt_set_int(c, "rc-lookahead", 0, 0);
568  av_opt_set_int(c, "fast-pskip", 1, 0);
569  av_opt_set_int(c, "mixed-refs", 1, 0);
570  av_opt_set_int(c, "8x8dct", 0, 0);
571  av_opt_set_int(c, "weightb", 0, 0);
572 
573  // libx264 AVOptions:
574  av_opt_set(c->priv_data, "preset",
575  m_encodingPreset.toLatin1().constData(), 0);
576  av_opt_set(c->priv_data, "tune",
577  m_encodingTune.toLatin1().constData(), 0);
578  }
579 
580  if(m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
581  c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
582 
583  return st;
584 }
585 
587 {
588  AVCodecContext *c;
589 
591 
592  if (!m_width || !m_height)
593  return false;
594 
595  if (avcodec_open2(c, nullptr, nullptr) < 0)
596  {
597  LOG(VB_RECORD, LOG_ERR,
598  LOC + "OpenVideo(): avcodec_open() failed");
599  return false;
600  }
601 
602  if (!m_picture)
603  {
604  m_picture = AllocPicture(c->pix_fmt);
605  if (!m_picture)
606  {
607  LOG(VB_RECORD, LOG_ERR,
608  LOC + "OpenVideo(): AllocPicture() failed");
609  return false;
610  }
611  }
612  else
613  {
614  av_frame_unref(m_picture);
615  }
616 
617  return true;
618 }
619 
621 {
622  AVCodecContext *c;
623  AVStream *st;
624 
625  st = avformat_new_stream(m_ctx, nullptr);
626  if (!st)
627  {
628  LOG(VB_RECORD, LOG_ERR,
629  LOC + "AddAudioStream(): avformat_new_stream() failed");
630  return nullptr;
631  }
632  st->id = 1;
633 
634  c = gCodecMap->getCodecContext(st, nullptr, true);
635 
636  c->codec_id = m_ctx->oformat->audio_codec;
637  c->codec_type = AVMEDIA_TYPE_AUDIO;
638  c->bit_rate = m_audioBitrate;
639  c->sample_rate = m_audioFrameRate;
640  c->channels = m_audioChannels;
641 
642  // c->flags |= CODEC_FLAG_QSCALE; // VBR
643  // c->global_quality = blah;
644 
645  if (!m_avVideoCodec)
646  {
647  c->time_base = GetCodecTimeBase();
648  st->time_base.den = 90000;
649  st->time_base.num = 1;
650  }
651 
652  if(m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
653  c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
654 
655  return st;
656 }
657 
658 bool AVFormatWriter::FindAudioFormat(AVCodecContext *ctx, AVCodec *c, AVSampleFormat format)
659 {
660  if (c->sample_fmts)
661  {
662  for (int i = 0; c->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++)
663  {
664  if (av_get_packed_sample_fmt(c->sample_fmts[i]) == format)
665  {
666  ctx->sample_fmt = c->sample_fmts[i];
667  return true;
668  }
669  }
670  }
671  return false;
672 }
673 
675 {
676  AVCodecContext *c;
677  AVCodec *codec;
678 
680 
681  c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
682 
683  codec = avcodec_find_encoder(c->codec_id);
684  if (!codec)
685  {
686  LOG(VB_RECORD, LOG_ERR,
687  LOC + "OpenAudio(): avcodec_find_encoder() failed");
688  return false;
689  }
690 
691  // try to find suitable format we can use. avcodec_open2 will fail if we don't
692  // find one, so no need to worry otherwise. Can only handle S16 or FLOAT
693  // we give priority to S16 as libmp3lame requires aligned floats which we can't guarantee
694  if (!FindAudioFormat(c, codec, AV_SAMPLE_FMT_S16))
695  {
696  FindAudioFormat(c, codec, AV_SAMPLE_FMT_FLT);
697  }
698 
699  if (avcodec_open2(c, codec, nullptr) < 0)
700  {
701  LOG(VB_RECORD, LOG_ERR,
702  LOC + "OpenAudio(): avcodec_open() failed");
703  return false;
704  }
705 
706  m_audioFrameSize = c->frame_size; // number of *samples* per channel in an AVFrame
707 
708  m_audPicture = av_frame_alloc();
709  if (!m_audPicture)
710  {
711  LOG(VB_RECORD, LOG_ERR,
712  LOC + "OpenAudio(): alloc_frame() failed");
713  return false;
714  }
715 
716  int samples_per_frame = m_audioFrameSize * m_audioChannels;
717  int bps = av_get_bytes_per_sample(c->sample_fmt);
718  if (av_get_packed_sample_fmt(c->sample_fmt) == AV_SAMPLE_FMT_FLT)
719  {
720  // allocate buffer to convert from S16 to float
721  if (!(m_audioInBuf = (unsigned char*)av_malloc(bps * samples_per_frame)))
722  return false;
723  }
724  if (av_sample_fmt_is_planar(c->sample_fmt))
725  {
726  // allocate buffer to convert interleaved to planar audio
727  if (!(m_audioInPBuf = (unsigned char*)av_malloc(bps * samples_per_frame)))
728  return false;
729  }
730  return true;
731 }
732 
733 AVFrame* AVFormatWriter::AllocPicture(enum AVPixelFormat pix_fmt)
734 {
735  AVFrame *picture;
736  unsigned char *picture_buf;
737  int size;
738 
739  picture = av_frame_alloc();
740  if (!picture)
741  {
742  LOG(VB_RECORD, LOG_ERR,
743  LOC + "AllocPicture(): avcodec_alloc_frame() failed");
744  return nullptr;
745  }
746  size = av_image_get_buffer_size(pix_fmt, m_width, m_height, IMAGE_ALIGN);
747  picture_buf = (unsigned char *)av_malloc(size);
748  if (!picture_buf)
749  {
750  LOG(VB_RECORD, LOG_ERR, LOC + "AllocPicture(): av_malloc() failed");
751  av_frame_free(&picture);
752  return nullptr;
753  }
754  av_image_fill_arrays(picture->data, picture->linesize,
755  picture_buf, pix_fmt, m_width, m_height, IMAGE_ALIGN);
756  return picture;
757 }
758 
760 {
761  AVRational result;
762 
763  result.den = (int)floor(m_frameRate * 100);
764  result.num = 100;
765 
766  if (m_avVideoCodec && m_avVideoCodec->supported_framerates) {
767  const AVRational *p= m_avVideoCodec->supported_framerates;
768  AVRational req = {result.den, result.num};
769  const AVRational *best = nullptr;
770  AVRational best_error= {INT_MAX, 1};
771  for(; p->den!=0; p++) {
772  AVRational error = av_sub_q(req, *p);
773  if (error.num <0)
774  error.num *= -1;
775  if (av_cmp_q(error, best_error) < 0) {
776  best_error = error;
777  best = p;
778  }
779  }
780 
781  if (best && best->num && best->den)
782  {
783  result.den = best->num;
784  result.num = best->den;
785  }
786  }
787 
788  if (result.den == 2997)
789  {
790  result.den = 30000;
791  result.num = 1001;
792  }
793  else if (result.den == 5994)
794  {
795  result.den = 60000;
796  result.num = 1001;
797  }
798 
799  return result;
800 }
801 
802 /* vim: set expandtab tabstop=4 shiftwidth=4: */
int WriteAudioFrame(unsigned char *buf, int fnum, long long &timecode) override
AVStream * m_audioStream
static int toFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert integer samples to floats.
QString GetLastError(void) const
QString m_videoCodec
static void error(const char *str,...)
Definition: vbi.c:41
QString m_filename
struct AVFrame AVFrame
void freeCodecContext(const AVStream *)
Definition: mythavutil.cpp:427
bool Init(void) override
static RingBuffer * Create(const QString &xfilename, bool write, bool usereadahead=true, int timeout_ms=kDefaultOpenTimeout, bool stream_only=false)
Creates a RingBuffer instance.
Definition: ringbuffer.cpp:112
int WriteTextFrame(int vbimode, unsigned char *buf, int len, long long timecode, int pagenr) override
long long timecode
Definition: mythframe.h:49
bool FindAudioFormat(AVCodecContext *ctx, AVCodec *c, AVSampleFormat format)
AVCodec * m_avVideoCodec
long long m_startingTimecodeOffset
#define IMAGE_ALIGN
Definition: mythconfig.h:19
unsigned char * m_audioInBuf
AVFrame * AllocPicture(enum AVPixelFormat pix_fmt)
bool OpenAudio(void)
AVStream * AddVideoStream(void)
int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
AVPictureFill Initialise AVFrame pic with content from VideoFrame frame.
Definition: mythavutil.cpp:65
QString m_container
bool CloseFile(void) override
MythCodecMap * gCodecMap
This global variable contains the MythCodecMap instance for the app.
Definition: mythavutil.cpp:377
QString m_encodingPreset
AVFRingBuffer * m_avfRingBuffer
QList< long long > m_bufferedVideoFrameTimes
static int SampleSize(AudioFormat format)
long long m_framesWritten
int WriteVideoFrame(VideoFrame *frame) override
QString m_audioCodec
RingBuffer * m_ringBuffer
AVCodecContext * getCodecContext(const AVStream *, const AVCodec *pCodec=nullptr, bool nullCodec=false)
Definition: mythavutil.cpp:388
void Cleanup(void)
void * av_malloc(unsigned int size)
AVRational GetCodecTimeBase(void)
AVFrame * m_audPicture
static URLProtocol * GetRingBufferURLProtocol(void)
QString m_encodingTune
bool ReOpen(QString filename)
AVCodec * m_avAudioCodec
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QMutex * avcodeclock
This global variable is used to makes certain calls to avlib threadsafe.
#define LOC
bool NextFrameIsKeyFrame(void)
unsigned char * m_audioInPBuf
AVStream * AddAudioStream(void)
bool OpenFile(void) override
QList< long long > m_bufferedAudioFrameTimes
QList< int > m_bufferedVideoFrameTypes
AVFormatContext * m_ctx
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
AVOutputFormat m_fmt
AVFrame * m_picture
bool OpenVideo(void)
virtual bool ReOpen(QString="")
static void DeinterleaveSamples(AudioFormat format, int channels, uint8_t *output, const uint8_t *input, int data_size)
Deinterleave input samples Deinterleave audio samples and compact them.
AVStream * m_videoStream