MythTV  master
transcode.cpp
Go to the documentation of this file.
1 #include <cmath>
2 #include <fcntl.h>
3 #include <iostream>
4 #include <memory>
5 
6 #include <QStringList>
7 #include <QMap>
8 #include <QRegExp>
9 #include <QList>
10 #include <QWaitCondition>
11 #include <QMutex>
12 #include <QMutexLocker>
13 #include <QtAlgorithms>
14 
15 #include "mythconfig.h"
16 
17 #include "transcode.h"
18 #include "audiooutput.h"
19 #include "recordingprofile.h"
20 #include "mythcorecontext.h"
21 #include "jobqueue.h"
22 #include "exitcodes.h"
23 #include "mthreadpool.h"
24 #include "deletemap.h"
25 #include "tvremoteutil.h"
26 
27 #if CONFIG_LIBMP3LAME
28 #include "NuppelVideoRecorder.h"
29 #endif
30 #include "mythplayer.h"
31 #include "programinfo.h"
32 #include "mythdbcon.h"
33 #include "io/mythavformatwriter.h"
34 #include "HLS/httplivestream.h"
35 
36 #include "videodecodebuffer.h"
37 #include "cutter.h"
38 #include "audioreencodebuffer.h"
39 
40 extern "C" {
41 #include "libavcodec/avcodec.h"
42 #include "libswscale/swscale.h"
43 }
44 #include "mythavutil.h"
45 
46 #include <unistd.h> // for unlink()
47 
48 using namespace std;
49 
50 #define LOC QString("Transcode: ")
51 
53  m_proginfo(pginfo),
54  m_recProfile(new RecordingProfile("Transcoders"))
55 {
56 }
57 
59 {
60 #if CONFIG_LIBMP3LAME
61  delete m_nvr;
62 #endif
63  SetPlayerContext(nullptr);
64  delete m_outBuffer;
65  delete m_fifow;
66  delete m_kfaTable;
67  delete m_recProfile;
68 }
69 void Transcode::ReencoderAddKFA(long curframe, long lastkey, long num_keyframes)
70 {
71  long delta = curframe - lastkey;
72  if (delta != 0 && delta != m_keyframeDist)
73  {
74  struct kfatable_entry kfate {};
75  kfate.adjust = m_keyframeDist - delta;
76  kfate.keyframe_number = num_keyframes;
77  m_kfaTable->push_back(kfate);
78  }
79 }
80 
81 bool Transcode::GetProfile(const QString& profileName, const QString& encodingType,
82  int height, int frameRate)
83 {
84  if (profileName.toLower() == "autodetect")
85  {
86  if (height == 1088)
87  height = 1080;
88 
89  QString autoProfileName = QObject::tr("Autodetect from %1").arg(height);
90  if (frameRate == 25 || frameRate == 30)
91  autoProfileName += "i";
92  if (frameRate == 50 || frameRate == 60)
93  autoProfileName += "p";
94 
95  bool result = false;
96  LOG(VB_GENERAL, LOG_NOTICE,
97  QString("Transcode: Looking for autodetect profile: %1")
98  .arg(autoProfileName));
99  result = m_recProfile->loadByGroup(autoProfileName, "Transcoders");
100 
101  if (!result && encodingType == "MPEG-2")
102  {
103  result = m_recProfile->loadByGroup("MPEG2", "Transcoders");
104  autoProfileName = "MPEG2";
105  }
106  if (!result && (encodingType == "MPEG-4" || encodingType == "RTjpeg"))
107  {
108  result = m_recProfile->loadByGroup("RTjpeg/MPEG4",
109  "Transcoders");
110  autoProfileName = "RTjpeg/MPEG4";
111  }
112  if (!result)
113  {
114  LOG(VB_GENERAL, LOG_ERR,
115  QString("Transcode: Couldn't find profile for : %1")
116  .arg(encodingType));
117 
118  return false;
119  }
120 
121  LOG(VB_GENERAL, LOG_NOTICE,
122  QString("Transcode: Using autodetect profile: %1")
123  .arg(autoProfileName));
124  }
125  else
126  {
127  bool isNum = false;
128  int profileID = profileName.toInt(&isNum);
129  // If a bad profile is specified, there will be trouble
130  if (isNum && profileID > 0)
131  m_recProfile->loadByID(profileID);
132  else if (!m_recProfile->loadByGroup(profileName, "Transcoders"))
133  {
134  LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find profile #: %1")
135  .arg(profileName));
136  return false;
137  }
138  }
139  return true;
140 }
141 
143 {
144  if (player_ctx == m_ctx)
145  return;
146 
147  delete m_ctx;
148  m_ctx = player_ctx;
149 }
150 
151 #if CONFIG_LIBMP3LAME
152 static QString get_str_option(RecordingProfile *profile, const QString &name)
153 {
154  const StandardSetting *setting = profile->byName(name);
155  if (setting)
156  return setting->getValue();
157 
158  LOG(VB_GENERAL, LOG_ERR, LOC +
159  QString("get_str_option(...%1): Option not in profile.").arg(name));
160 
161  return QString();
162 }
163 
164 static int get_int_option(RecordingProfile *profile, const QString &name)
165 {
166  QString ret_str = get_str_option(profile, name);
167  if (ret_str.isEmpty())
168  return 0;
169 
170  bool ok = false;
171  int ret_int = ret_str.toInt(&ok);
172 
173  if (!ok)
174  {
175  LOG(VB_GENERAL, LOG_ERR, LOC +
176  QString("get_int_option(...%1): Option is not an int.").arg(name));
177  }
178 
179  return ret_int;
180 }
181 
182 static bool get_bool_option(RecordingProfile *profile, const QString &name)
183 {
184  return get_int_option(profile, name) != 0;
185 }
186 
187 static void TranscodeWriteText(void *ptr, unsigned char *buf, int len,
188  int timecode, int pagenr)
189 {
190  auto *nvr = (NuppelVideoRecorder *)ptr;
191  nvr->WriteText(buf, len, timecode, pagenr);
192 }
193 #endif // CONFIG_LIBMP3LAME
194 
195 int Transcode::TranscodeFile(const QString &inputname,
196  const QString &outputname,
197  const QString &profileName,
198  bool honorCutList, bool framecontrol,
199  int jobID, const QString& fifodir,
200  bool fifo_info, bool cleanCut,
201  frm_dir_map_t &deleteMap,
202  int AudioTrackNo,
203  bool passthru)
204 {
205  QDateTime curtime = MythDate::current();
206  QDateTime statustime = curtime;
207  int audioFrame = 0;
208  std::unique_ptr<Cutter> cutter = nullptr;
209  std::unique_ptr<MythAVFormatWriter> avfw = nullptr;
210  std::unique_ptr<MythAVFormatWriter> avfw2 = nullptr;
211  std::unique_ptr<HTTPLiveStream> hls = nullptr;
212  int hlsSegmentSize = 0;
213  int hlsSegmentFrames = 0;
214 
215 #if !CONFIG_LIBMP3LAME
216  (void)profileName;
217 #endif
218 
219  if (jobID >= 0)
220  JobQueue::ChangeJobComment(jobID, "0% " + QObject::tr("Completed"));
221 
222  if (m_hlsMode)
223  {
224  m_avfMode = true;
225 
226  if (m_hlsStreamID != -1)
227  {
228  hls = std::make_unique<HTTPLiveStream>(m_hlsStreamID);
229  hls->UpdateStatus(kHLSStatusStarting);
230  hls->UpdateStatusMessage("Transcoding Starting");
231  m_cmdWidth = hls->GetWidth();
232  m_cmdHeight = hls->GetHeight();
233  m_cmdBitrate = hls->GetBitrate();
234  m_cmdAudioBitrate = hls->GetAudioBitrate();
235  }
236  }
237 
238  if (!m_avfMode)
239  {
240 #if CONFIG_LIBMP3LAME
241  m_nvr = new NuppelVideoRecorder(nullptr, nullptr);
242 #else
243  LOG(VB_GENERAL, LOG_ERR,
244  "Not compiled with libmp3lame support");
245  return REENCODE_ERROR;
246 #endif
247  }
248 
249  // Input setup
250  auto *player_ctx = new PlayerContext(kTranscoderInUseID);
251  player_ctx->SetPlayingInfo(m_proginfo);
252  MythMediaBuffer *rb = (hls && (m_hlsStreamID != -1)) ?
253  MythMediaBuffer::Create(hls->GetSourceFile(), false, false) :
254  MythMediaBuffer::Create(inputname, false, false);
255  if (!rb || !rb->GetLastError().isEmpty())
256  {
257  LOG(VB_GENERAL, LOG_ERR,
258  QString("Transcoding aborted, error: '%1'")
259  .arg(rb? rb->GetLastError() : ""));
260  delete player_ctx;
261  return REENCODE_ERROR;
262  }
263  player_ctx->SetRingBuffer(rb);
264  player_ctx->SetPlayer(new MythPlayer((PlayerFlags)(kVideoIsNull | kNoITV)));
265  SetPlayerContext(player_ctx);
266  GetPlayer()->SetPlayerInfo(nullptr, nullptr, GetPlayerContext());
267  if (m_proginfo->GetRecordingEndTime() > curtime)
268  {
269  player_ctx->SetRecorder(RemoteGetExistingRecorder(m_proginfo));
271  }
272 
273  if (m_showProgress)
274  {
275  statustime = statustime.addSecs(5);
276  }
277 
278  AudioOutput *audioOutput = new AudioReencodeBuffer(FORMAT_NONE, 0,
279  passthru);
280  AudioReencodeBuffer *arb = ((AudioReencodeBuffer*)audioOutput);
281  GetPlayer()->GetAudio()->SetAudioOutput(audioOutput);
282  GetPlayer()->SetTranscoding(true);
283 
284  if (GetPlayer()->OpenFile() < 0)
285  {
286  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, error opening file.");
287  SetPlayerContext(nullptr);
288  return REENCODE_ERROR;
289  }
290 
291  if (AudioTrackNo > -1)
292  {
293  LOG(VB_GENERAL, LOG_INFO,
294  QString("Set audiotrack number to %1").arg(AudioTrackNo));
295  GetPlayer()->GetDecoder()->SetTrack(kTrackTypeAudio, AudioTrackNo);
296  }
297 
298  long long total_frame_count = GetPlayer()->GetTotalFrameCount();
299  long long new_frame_count = total_frame_count;
300  if (honorCutList && m_proginfo)
301  {
302  LOG(VB_GENERAL, LOG_INFO, "Honoring the cutlist while transcoding");
303 
304  frm_dir_map_t::const_iterator it;
305  QString cutStr;
306  long long lastStart = 0;
307 
308  if (deleteMap.empty())
309  m_proginfo->QueryCutList(deleteMap);
310 
311  for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
312  {
313  if (*it)
314  {
315  if (!cutStr.isEmpty())
316  cutStr += ",";
317  cutStr += QString("%1-").arg((long)it.key());
318  lastStart = it.key();
319  }
320  else
321  {
322  if (cutStr.isEmpty())
323  cutStr += "0-";
324  cutStr += QString("%1").arg((long)it.key());
325  new_frame_count -= (it.key() - lastStart);
326  }
327  }
328  if (cutStr.isEmpty())
329  cutStr = "Is Empty";
330  else if (cutStr.endsWith('-') && (total_frame_count > lastStart))
331  {
332  new_frame_count -= (total_frame_count - lastStart);
333  cutStr += QString("%1").arg(total_frame_count);
334  }
335  LOG(VB_GENERAL, LOG_INFO, QString("Cutlist : %1").arg(cutStr));
336  LOG(VB_GENERAL, LOG_INFO, QString("Original Length: %1 frames")
337  .arg((long)total_frame_count));
338  LOG(VB_GENERAL, LOG_INFO, QString("New Length : %1 frames")
339  .arg((long)new_frame_count));
340 
341  if ((m_proginfo->QueryIsEditing()) ||
343  {
344  LOG(VB_GENERAL, LOG_INFO, "Transcoding aborted, cutlist changed");
345  SetPlayerContext(nullptr);
347  }
349  curtime = curtime.addSecs(60);
350  }
351 
353  QString encodingType = GetPlayer()->GetEncodingType();
354  bool copyvideo = false;
355  bool copyaudio = false;
356 
357  QString vidsetting = nullptr;
358  QString audsetting = nullptr;
359  QString vidfilters = nullptr;
360 
361  QSize buf_size = GetPlayer()->GetVideoBufferSize();
362  int video_width = buf_size.width();
363  int video_height = buf_size.height();
364 
365  if (video_height == 1088) {
366  LOG(VB_GENERAL, LOG_NOTICE,
367  "Found video height of 1088. This is unusual and "
368  "more than likely the video is actually 1080 so mythtranscode "
369  "will treat it as such.");
370  }
371 
372  DecoderBase* dec = GetPlayer()->GetDecoder();
373  float video_aspect = dec ? dec->GetVideoAspect() : 4.0F / 3.0F;
374  float video_frame_rate = GetPlayer()->GetFrameRate();
375  int newWidth = video_width;
376  int newHeight = video_height;
377  bool halfFramerate = false;
378  bool skippedLastFrame = false;
379 
380  m_kfaTable = new vector<struct kfatable_entry>;
381 
382  if (m_avfMode)
383  {
384  newWidth = m_cmdWidth;
385  newHeight = m_cmdHeight;
386 
387  // Absolutely no purpose is served by scaling video up beyond it's
388  // original resolution, quality is degraded, transcoding is
389  // slower and in future we may wish to scale bitrate according to
390  // resolution, so it would also waste bandwidth (when streaming)
391  //
392  // This change could be said to apply for all transcoding, but for now
393  // we're limiting it to HLS where it's uncontroversial
394  if (m_hlsMode)
395  {
396 // if (newWidth > video_width)
397 // newWidth = video_width;
398  if (newHeight > video_height)
399  {
400  newHeight = video_height;
401  newWidth = 0;
402  }
403  }
404 
405  // TODO: is this necessary? It got commented out, but may still be
406  // needed.
407  // int actualHeight = (video_height == 1088 ? 1080 : video_height);
408 
409  // If height or width are 0, then we need to calculate them
410  if (newHeight == 0 && newWidth > 0)
411  newHeight = (int)(1.0F * newWidth / video_aspect);
412  else if (newWidth == 0 && newHeight > 0)
413  newWidth = (int)(1.0F * newHeight * video_aspect);
414  else if (newWidth == 0 && newHeight == 0)
415  {
416  newHeight = 480;
417  newWidth = (int)(1.0F * 480 * video_aspect);
418  if (newWidth > 640)
419  {
420  newWidth = 640;
421  newHeight = (int)(1.0F * 640 / video_aspect);
422  }
423  }
424 
425  // make sure dimensions are valid for MPEG codecs
426  newHeight = (newHeight + 15) & ~0xF;
427  newWidth = (newWidth + 15) & ~0xF;
428 
429  avfw = std::make_unique<MythAVFormatWriter>();
430  if (!avfw)
431  {
432  LOG(VB_GENERAL, LOG_ERR,
433  "Transcoding aborted, error creating AVFormatWriter.");
434  SetPlayerContext(nullptr);
435  return REENCODE_ERROR;
436  }
437 
438  avfw->SetVideoBitrate(m_cmdBitrate);
439  avfw->SetHeight(newHeight);
440  avfw->SetWidth(newWidth);
441  avfw->SetAspect(video_aspect);
442  avfw->SetAudioBitrate(m_cmdAudioBitrate);
443  avfw->SetAudioChannels(arb->m_channels);
444  avfw->SetAudioFrameRate(arb->m_eff_audiorate);
445  avfw->SetAudioFormat(FORMAT_S16);
446 
447  if (m_hlsMode)
448  {
449 
450  if (m_hlsStreamID == -1)
451  {
452  hls = std::make_unique<HTTPLiveStream>(inputname, newWidth, newHeight,
454  m_hlsMaxSegments, 0, 0);
455 
456  m_hlsStreamID = hls->GetStreamID();
457  if (!hls || m_hlsStreamID == -1)
458  {
459  LOG(VB_GENERAL, LOG_ERR, "Unable to create new stream");
460  SetPlayerContext(nullptr);
461  return REENCODE_ERROR;
462  }
463  }
464 
465  int segmentSize = hls->GetSegmentSize();
466 
467  LOG(VB_GENERAL, LOG_NOTICE,
468  QString("HLS: Using segment size of %1 seconds")
469  .arg(segmentSize));
470 
472  {
473  int audioOnlyBitrate = hls->GetAudioOnlyBitrate();
474 
475  avfw2 = std::make_unique<MythAVFormatWriter>();
476  avfw2->SetContainer("mpegts");
477  avfw2->SetAudioCodec("aac");
478  avfw2->SetAudioBitrate(audioOnlyBitrate);
479  avfw2->SetAudioChannels(arb->m_channels);
480  avfw2->SetAudioFrameRate(arb->m_eff_audiorate);
481  avfw2->SetAudioFormat(FORMAT_S16);
482  }
483 
484  avfw->SetContainer("mpegts");
485  avfw->SetVideoCodec("libx264");
486  avfw->SetAudioCodec("aac");
487  hls->UpdateStatus(kHLSStatusStarting);
488  hls->UpdateStatusMessage("Transcoding Starting");
489  hls->UpdateSizeInfo(newWidth, newHeight, video_width, video_height);
490 
491  if (!hls->InitForWrite())
492  {
493  LOG(VB_GENERAL, LOG_ERR, "hls->InitForWrite() failed");
494  SetPlayerContext(nullptr);
495  return REENCODE_ERROR;
496  }
497 
498  if (video_frame_rate > 30)
499  {
500  halfFramerate = true;
501  avfw->SetFramerate(video_frame_rate/2);
502 
503  if (avfw2)
504  avfw2->SetFramerate(video_frame_rate/2);
505 
506  hlsSegmentSize = (int)(segmentSize * video_frame_rate / 2);
507  }
508  else
509  {
510  avfw->SetFramerate(video_frame_rate);
511 
512  if (avfw2)
513  avfw2->SetFramerate(video_frame_rate);
514 
515  hlsSegmentSize = (int)(segmentSize * video_frame_rate);
516  }
517 
518  avfw->SetKeyFrameDist(30);
519  if (avfw2)
520  avfw2->SetKeyFrameDist(30);
521 
522  hls->AddSegment();
523  avfw->SetFilename(hls->GetCurrentFilename());
524  if (avfw2)
525  avfw2->SetFilename(hls->GetCurrentFilename(true));
526  }
527  else
528  {
529  avfw->SetContainer(m_cmdContainer);
530  avfw->SetVideoCodec(m_cmdVideoCodec);
531  avfw->SetAudioCodec(m_cmdAudioCodec);
532  avfw->SetFilename(outputname);
533  avfw->SetFramerate(video_frame_rate);
534  avfw->SetKeyFrameDist(30);
535  }
536 
537  int threads = gCoreContext->GetNumSetting("HTTPLiveStreamThreads", 2);
538  QString preset = gCoreContext->GetSetting("HTTPLiveStreamPreset", "veryfast");
539  QString tune = gCoreContext->GetSetting("HTTPLiveStreamTune", "film");
540 
541  LOG(VB_GENERAL, LOG_NOTICE,
542  QString("x264 HLS using: %1 threads, '%2' profile and '%3' tune")
543  .arg(threads).arg(preset).arg(tune));
544 
545  avfw->SetThreadCount(threads);
546  avfw->SetEncodingPreset(preset);
547  avfw->SetEncodingTune(tune);
548 
549  if (avfw2)
550  avfw2->SetThreadCount(1);
551 
552  if (!avfw->Init())
553  {
554  LOG(VB_GENERAL, LOG_ERR, "avfw->Init() failed");
555  SetPlayerContext(nullptr);
556  return REENCODE_ERROR;
557  }
558 
559  if (!avfw->OpenFile())
560  {
561  LOG(VB_GENERAL, LOG_ERR, "avfw->OpenFile() failed");
562  SetPlayerContext(nullptr);
563  return REENCODE_ERROR;
564  }
565 
566  if (avfw2 && !avfw2->Init())
567  {
568  LOG(VB_GENERAL, LOG_ERR, "avfw2->Init() failed");
569  SetPlayerContext(nullptr);
570  return REENCODE_ERROR;
571  }
572 
573  if (avfw2 && !avfw2->OpenFile())
574  {
575  LOG(VB_GENERAL, LOG_ERR, "avfw2->OpenFile() failed");
576  SetPlayerContext(nullptr);
577  return REENCODE_ERROR;
578  }
579 
580  arb->m_audioFrameSize = avfw->GetAudioFrameSize() * arb->m_channels * 2;
581  }
582 #if CONFIG_LIBMP3LAME
583  else if (fifodir.isEmpty())
584  {
585  if (!GetProfile(profileName, encodingType, video_height,
586  (int)round(video_frame_rate))) {
587  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, no profile found.");
588  SetPlayerContext(nullptr);
589  return REENCODE_ERROR;
590  }
591 
592  // For overriding settings on the command line
593  QMap<QString, QString> recorderOptionsMap;
594  if (!m_recorderOptions.isEmpty())
595  {
596 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
597  QStringList options = m_recorderOptions
598  .split(",", QString::SkipEmptyParts);
599 #else
600  QStringList options = m_recorderOptions
601  .split(",", Qt::SkipEmptyParts);
602 #endif
603  int loop = 0;
604  while (loop < options.size())
605  {
606  QStringList tokens = options[loop].split("=");
607  if (tokens.length() < 2)
608  {
609  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, invalid option settings.");
610  return REENCODE_ERROR;
611  }
612  recorderOptionsMap[tokens[0]] = tokens[1];
613 
614  loop++;
615  }
616  }
617 
618  vidsetting = get_str_option(m_recProfile, "videocodec");
619  audsetting = get_str_option(m_recProfile, "audiocodec");
620  vidfilters = get_str_option(m_recProfile, "transcodefilters");
621 
622  if (encodingType == "MPEG-2" &&
623  get_bool_option(m_recProfile, "transcodelossless"))
624  {
625  LOG(VB_GENERAL, LOG_NOTICE, "Switching to MPEG-2 transcoder.");
626  SetPlayerContext(nullptr);
627  return REENCODE_MPEG2TRANS;
628  }
629 
630  // Recorder setup
631  if (get_bool_option(m_recProfile, "transcodelossless"))
632  {
633  vidsetting = encodingType;
634  audsetting = "MP3";
635  }
636  else if (get_bool_option(m_recProfile, "transcoderesize"))
637  {
638  int actualHeight = (video_height == 1088 ? 1080 : video_height);
639 
640  //GetPlayer()->SetVideoFilters(vidfilters);
641  newWidth = get_int_option(m_recProfile, "width");
642  newHeight = get_int_option(m_recProfile, "height");
643 
644  // If height or width are 0, then we need to calculate them
645  if (newHeight == 0 && newWidth > 0)
646  newHeight = (int)(1.0 * newWidth * actualHeight / video_width);
647  else if (newWidth == 0 && newHeight > 0)
648  newWidth = (int)(1.0 * newHeight * video_width / actualHeight);
649  else if (newWidth == 0 && newHeight == 0)
650  {
651  newHeight = 480;
652  newWidth = (int)(1.0 * 480 * video_width / actualHeight);
653  if (newWidth > 640)
654  {
655  newWidth = 640;
656  newHeight = (int)(1.0 * 640 * actualHeight / video_width);
657  }
658  }
659 
660  if (encodingType.startsWith("mpeg", Qt::CaseInsensitive))
661  {
662  // make sure dimensions are valid for MPEG codecs
663  newHeight = (newHeight + 15) & ~0xF;
664  newWidth = (newWidth + 15) & ~0xF;
665  }
666 
667  LOG(VB_GENERAL, LOG_INFO, QString("Resizing from %1x%2 to %3x%4")
668  .arg(video_width).arg(video_height)
669  .arg(newWidth).arg(newHeight));
670  }
671  else // lossy and no resize
672  {
673  //GetPlayer()->SetVideoFilters(vidfilters);
674  }
675 
676  // this is ripped from tv_rec SetupRecording. It'd be nice to merge
677  m_nvr->SetOption("inpixfmt", FMT_YV12);
678 
679  m_nvr->SetOption("width", newWidth);
680  m_nvr->SetOption("height", newHeight);
681 
682  m_nvr->SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
683  m_nvr->SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
684 
685  m_nvr->SetFrameRate(video_frame_rate);
686  m_nvr->SetVideoAspect(video_aspect);
687  m_nvr->SetTranscoding(true);
688 
689  if ((vidsetting == "MPEG-4") ||
690  (recorderOptionsMap["videocodec"] == "mpeg4"))
691  {
692  m_nvr->SetOption("videocodec", "mpeg4");
693 
694  m_nvr->SetIntOption(m_recProfile, "mpeg4bitrate");
695  m_nvr->SetIntOption(m_recProfile, "scalebitrate");
696  m_nvr->SetIntOption(m_recProfile, "mpeg4maxquality");
697  m_nvr->SetIntOption(m_recProfile, "mpeg4minquality");
698  m_nvr->SetIntOption(m_recProfile, "mpeg4qualdiff");
699  m_nvr->SetIntOption(m_recProfile, "mpeg4optionvhq");
700  m_nvr->SetIntOption(m_recProfile, "mpeg4option4mv");
701 #ifdef USING_FFMPEG_THREADS
702  m_nvr->SetIntOption(m_recProfile, "encodingthreadcount");
703 #endif
704  }
705  else if ((vidsetting == "MPEG-2") ||
706  (recorderOptionsMap["videocodec"] == "mpeg2video"))
707  {
708  m_nvr->SetOption("videocodec", "mpeg2video");
709 
710  m_nvr->SetIntOption(m_recProfile, "mpeg2bitrate");
711  m_nvr->SetIntOption(m_recProfile, "scalebitrate");
712 #ifdef USING_FFMPEG_THREADS
713  m_nvr->SetIntOption(m_recProfile, "encodingthreadcount");
714 #endif
715  }
716  else if ((vidsetting == "RTjpeg") ||
717  (recorderOptionsMap["videocodec"] == "rtjpeg"))
718  {
719  m_nvr->SetOption("videocodec", "rtjpeg");
720  m_nvr->SetIntOption(m_recProfile, "rtjpegquality");
721  m_nvr->SetIntOption(m_recProfile, "rtjpegchromafilter");
722  m_nvr->SetIntOption(m_recProfile, "rtjpeglumafilter");
723  }
724  else if (vidsetting.isEmpty())
725  {
726  LOG(VB_GENERAL, LOG_ERR, "No video information found!");
727  LOG(VB_GENERAL, LOG_ERR, "Please ensure that recording profiles "
728  "for the transcoder are set");
729  SetPlayerContext(nullptr);
730  return REENCODE_ERROR;
731  }
732  else
733  {
734  LOG(VB_GENERAL, LOG_ERR,
735  QString("Unknown video codec: %1").arg(vidsetting));
736  SetPlayerContext(nullptr);
737  return REENCODE_ERROR;
738  }
739 
740  m_nvr->SetOption("samplerate", arb->m_eff_audiorate);
741  if (audsetting == "MP3")
742  {
743  m_nvr->SetOption("audiocompression", 1);
744  m_nvr->SetIntOption(m_recProfile, "mp3quality");
745  copyaudio = true;
746  }
747  else if (audsetting == "Uncompressed")
748  {
749  m_nvr->SetOption("audiocompression", 0);
750  }
751  else
752  {
753  LOG(VB_GENERAL, LOG_ERR,
754  QString("Unknown audio codec: %1").arg(audsetting));
755  }
756 
757  m_nvr->AudioInit(true);
758 
759  // For overriding settings on the command line
760  if (!recorderOptionsMap.empty())
761  {
762  QMap<QString, QString>::Iterator it;
763  QString key;
764  QString value;
765  for (it = recorderOptionsMap.begin();
766  it != recorderOptionsMap.end(); ++it)
767  {
768  key = it.key();
769  value = *it;
770 
771  LOG(VB_GENERAL, LOG_NOTICE,
772  QString("Forcing Recorder option '%1' to '%2'")
773  .arg(key).arg(value));
774 
775  if (value.contains(QRegExp("[^0-9]")))
776  m_nvr->SetOption(key, value);
777  else
778  m_nvr->SetOption(key, value.toInt());
779 
780  if (key == "width")
781  newWidth = (value.toInt() + 15) & ~0xF;
782  else if (key == "height")
783  newHeight = (value.toInt() + 15) & ~0xF;
784  else if (key == "videocodec")
785  {
786  if (value == "mpeg4")
787  vidsetting = "MPEG-4";
788  else if (value == "mpeg2video")
789  vidsetting = "MPEG-2";
790  else if (value == "rtjpeg")
791  vidsetting = "RTjpeg";
792  }
793  }
794  }
795 
796  if ((vidsetting == "MPEG-4") ||
797  (vidsetting == "MPEG-2"))
798  m_nvr->SetupAVCodecVideo();
799  else if (vidsetting == "RTjpeg")
800  m_nvr->SetupRTjpeg();
801 
802  m_outBuffer = MythMediaBuffer::Create(outputname, true, false);
803  m_nvr->SetRingBuffer(m_outBuffer);
804  m_nvr->WriteHeader();
805  m_nvr->StreamAllocate();
806  }
807 
808  if (vidsetting == encodingType && !framecontrol && !m_avfMode &&
809  fifodir.isEmpty() && honorCutList &&
810  video_width == newWidth && video_height == newHeight)
811  {
812  copyvideo = true;
813  LOG(VB_GENERAL, LOG_INFO, "Reencoding video in 'raw' mode");
814  }
815 #endif // CONFIG_LIBMP3LAME
816 
817  if (honorCutList && !deleteMap.empty())
818  {
819  if (cleanCut)
820  {
821  // Have the player seek only part of the way
822  // through a cut, and then use the cutter to
823  // discard the rest
824  cutter = std::make_unique<Cutter>();
825  cutter->SetCutList(deleteMap, m_ctx);
826  GetPlayer()->SetCutList(cutter->AdjustedCutList());
827  }
828  else
829  {
830  // Have the player apply the cut list
831  GetPlayer()->SetCutList(deleteMap);
832  }
833  }
834 
835  GetPlayer()->InitForTranscode(copyaudio, copyvideo);
836  if (GetPlayer()->IsErrored())
837  {
838  LOG(VB_GENERAL, LOG_ERR,
839  "Unable to initialize MythPlayer for Transcode");
840  SetPlayerContext(nullptr);
841  return REENCODE_ERROR;
842  }
843 
844  // must come after InitForTranscode - which creates the VideoOutput instance
845  if (m_hlsMode)
847 
848  VideoFrame frame {};
849  memset(&frame, 0, sizeof(frame));
850  // Do not use padding when compressing to RTjpeg or when in fifomode.
851  // The RTjpeg compressor doesn't know how to handle strides different to
852  // video width.
853  // cppcheck-suppress knownConditionTrueFalse
854  bool nonAligned = vidsetting == "RTjpeg" || !fifodir.isEmpty();
855  bool rescale =
856  (video_width != newWidth) || (video_height != newHeight)
857  || nonAligned;
858 
859  if (rescale)
860  {
861  size_t newSize = 0;
862  if (nonAligned)
863  {
864  // Set a stride identical to actual width, to ease fifo post-conversion process.
865  // 1080i/p video is actually 1088 because of the 16x16 blocks so
866  // we have to fudge the output size here. nuvexport knows how to handle
867  // this and as of right now it is the only app that uses the fifo ability.
868  newSize = GetBufferSize(FMT_YV12, video_width, video_height == 1080 ? 1088 : video_height, 0 /* aligned */);
869  }
870  else
871  {
872  newSize = GetBufferSize(FMT_YV12, newWidth, newHeight);
873  }
874  unsigned char *newFrame = GetAlignedBuffer(newSize);
875  if (!newFrame)
876  {
877  // OOM
878  return REENCODE_ERROR;
879  }
880  if (nonAligned)
881  {
882  // Set a stride identical to actual width, to ease fifo post-conversion process.
883  init(&frame, FMT_YV12, newFrame, video_width, video_height,
884  static_cast<int>(newSize), nullptr, nullptr, -1, -1, 0 /* aligned */);
885  }
886  else
887  {
888  // use default stride size.
889  init(&frame, FMT_YV12, newFrame, newWidth, newHeight, static_cast<int>(newSize));
890  }
891  }
892 
893  if (!fifodir.isEmpty())
894  {
895  AudioPlayer *aplayer = GetPlayer()->GetAudio();
896  const char *audio_codec_name = "unknown";
897 
898  switch(aplayer->GetCodec())
899  {
900  case AV_CODEC_ID_AC3:
901  audio_codec_name = "ac3";
902  break;
903  case AV_CODEC_ID_EAC3:
904  audio_codec_name = "eac3";
905  break;
906  case AV_CODEC_ID_DTS:
907  audio_codec_name = "dts";
908  break;
909  case AV_CODEC_ID_TRUEHD:
910  audio_codec_name = "truehd";
911  break;
912  case AV_CODEC_ID_MP3:
913  audio_codec_name = "mp3";
914  break;
915  case AV_CODEC_ID_MP2:
916  audio_codec_name = "mp2";
917  break;
918  case AV_CODEC_ID_AAC:
919  audio_codec_name = "aac";
920  break;
921  case AV_CODEC_ID_AAC_LATM:
922  audio_codec_name = "aac_latm";
923  break;
924  default:
925  audio_codec_name = "unknown";
926  }
927 
928  if (!arb->m_passthru)
929  audio_codec_name = "raw";
930 
931  // If cutlist is used then get info on first uncut frame
932  if (honorCutList && fifo_info)
933  {
934  bool is_key = false;
935  int did_ff = 0;
936  GetPlayer()->TranscodeGetNextFrame(did_ff, is_key, true);
937 
938  QSize buf_size2 = GetPlayer()->GetVideoBufferSize();
939  video_width = buf_size2.width();
940  video_height = buf_size2.height();
941  video_aspect = GetPlayer()->GetVideoAspect();
942  video_frame_rate = GetPlayer()->GetFrameRate();
943  }
944 
945  // Display details of the format of the fifo data.
946  LOG(VB_GENERAL, LOG_INFO,
947  QString("FifoVideoWidth %1").arg(video_width));
948  LOG(VB_GENERAL, LOG_INFO,
949  QString("FifoVideoHeight %1").arg(video_height));
950  LOG(VB_GENERAL, LOG_INFO,
951  QString("FifoVideoAspectRatio %1").arg(video_aspect));
952  LOG(VB_GENERAL, LOG_INFO,
953  QString("FifoVideoFrameRate %1").arg(video_frame_rate));
954  LOG(VB_GENERAL, LOG_INFO,
955  QString("FifoAudioFormat %1").arg(audio_codec_name));
956  LOG(VB_GENERAL, LOG_INFO,
957  QString("FifoAudioChannels %1").arg(arb->m_channels));
958  LOG(VB_GENERAL, LOG_INFO,
959  QString("FifoAudioSampleRate %1").arg(arb->m_eff_audiorate));
960 
961  if(fifo_info)
962  {
963  // Request was for just the format of fifo data, not for
964  // the actual transcode, so stop here.
965  unlink(outputname.toLocal8Bit().constData());
966  SetPlayerContext(nullptr);
967  if (rescale)
968  {
969  av_freep(&frame.buf);
970  }
971  return REENCODE_OK;
972  }
973 
974  QString audfifo = fifodir + QString("/audout");
975  QString vidfifo = fifodir + QString("/vidout");
976  int audio_size = arb->m_eff_audiorate * arb->m_bytes_per_frame;
977  // framecontrol is true if we want to enforce fifo sync.
978  if (framecontrol)
979  LOG(VB_GENERAL, LOG_INFO, "Enforcing sync on fifos");
980  m_fifow = new MythFIFOWriter(2, framecontrol);
981 
982  if (!m_fifow->FIFOInit(0, QString("video"), vidfifo, frame.size, 50) ||
983  !m_fifow->FIFOInit(1, QString("audio"), audfifo, audio_size, 25))
984  {
985  LOG(VB_GENERAL, LOG_ERR,
986  "Error initializing fifo writer. Aborting");
987  unlink(outputname.toLocal8Bit().constData());
988  SetPlayerContext(nullptr);
989  if (rescale)
990  {
991  av_freep(&frame.buf);
992  }
993  return REENCODE_ERROR;
994  }
995  LOG(VB_GENERAL, LOG_INFO,
996  QString("Video %1x%2@%3fps Audio rate: %4")
997  .arg(video_width).arg(video_height)
998  .arg(video_frame_rate)
999  .arg(arb->m_eff_audiorate));
1000  LOG(VB_GENERAL, LOG_INFO, "Created fifos. Waiting for connection.");
1001  }
1002 
1003 #if CONFIG_LIBMP3LAME
1004  bool forceKeyFrames = (m_fifow == nullptr) ? framecontrol : false;
1005  bool writekeyframe = true;
1006  long lastKeyFrame = 0;
1007  int num_keyframes = 0;
1008 #endif
1009 
1010  frm_dir_map_t::iterator dm_iter;
1011 
1012  int did_ff = 0;
1013 
1014  long curFrameNum = 0;
1015  frame.frameNumber = 1;
1016  long totalAudio = 0;
1017  int dropvideo = 0;
1018  // timecode of the last read video frame in input time
1019  long long lasttimecode = 0;
1020  // timecode of the last write video frame in input or output time
1021  long long lastWrittenTime = 0;
1022  // delta between the same video frame in input and output due to applying the cut list
1023  long long timecodeOffset = 0;
1024 
1025  float rateTimeConv = arb->m_eff_audiorate / 1000.0F;
1026  float vidFrameTime = 1000.0F / video_frame_rate;
1027  int wait_recover = 0;
1028  MythVideoOutput *videoOutput = GetPlayer()->GetVideoOutput();
1029  bool is_key = false;
1030  bool first_loop = true;
1031  AVFrame imageIn;
1032  AVFrame imageOut;
1033  struct SwsContext *scontext = nullptr;
1034 
1035  if (m_fifow)
1036  LOG(VB_GENERAL, LOG_INFO, "Dumping Video and Audio data to fifos");
1037  else if (copyaudio)
1038  LOG(VB_GENERAL, LOG_INFO, "Copying Audio while transcoding Video");
1039  else if (m_hlsMode)
1040  LOG(VB_GENERAL, LOG_INFO, "Transcoding for HTTP Live Streaming");
1041  else if (m_avfMode)
1042  LOG(VB_GENERAL, LOG_INFO, "Transcoding to libavformat container");
1043  else
1044  LOG(VB_GENERAL, LOG_INFO, "Transcoding Video and Audio");
1045 
1046  auto *videoBuffer =
1047  new VideoDecodeBuffer(GetPlayer(), videoOutput, honorCutList);
1048  MThreadPool::globalInstance()->start(videoBuffer, "VideoDecodeBuffer");
1049 
1050  QElapsedTimer flagTime;
1051  flagTime.start();
1052 
1053  if (cutter)
1054  cutter->Activate(vidFrameTime * rateTimeConv, total_frame_count);
1055 
1056  bool stopSignalled = false;
1057  VideoFrame *lastDecode = nullptr;
1058 
1059  if (hls)
1060  {
1061  hls->UpdateStatus(kHLSStatusRunning);
1062  hls->UpdateStatusMessage("Transcoding");
1063  }
1064 
1065  while ((!stopSignalled) &&
1066  (lastDecode = videoBuffer->GetFrame(did_ff, is_key)))
1067  {
1068  if (first_loop)
1069  {
1070  copyaudio = GetPlayer()->GetRawAudioState();
1071  first_loop = false;
1072  }
1073 
1074  float new_aspect = lastDecode->aspect;
1075 
1076  if (cutter)
1077  cutter->NewFrame(lastDecode->frameNumber);
1078 
1079 // frame timecode is on input time base
1080  frame.timecode = lastDecode->timecode;
1081 
1082  // if the timecode jumps backwards just use the last frame's timecode plus the duration of a frame
1083  if (frame.timecode < lasttimecode)
1084  frame.timecode = (long long)(lasttimecode + vidFrameTime);
1085 
1086  if (m_fifow)
1087  {
1088  AVPictureFill(&imageIn, lastDecode);
1089  AVPictureFill(&imageOut, &frame);
1090 
1091  scontext = sws_getCachedContext(scontext,
1092  lastDecode->width, lastDecode->height, FrameTypeToPixelFormat(lastDecode->codec),
1093  frame.width, frame.height, FrameTypeToPixelFormat(frame.codec),
1094  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1095  // Typically, wee aren't rescaling per say, we're just correcting the stride set by the decoder.
1096  // However, it allows to properly handle recordings that see their resolution change half-way.
1097  sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1098  lastDecode->height, imageOut.data, imageOut.linesize);
1099 
1100  totalAudio += arb->GetSamples(frame.timecode);
1101  int audbufTime = (int)(totalAudio / rateTimeConv);
1102  int auddelta = frame.timecode - audbufTime;
1103  int vidTime = lroundf(curFrameNum * vidFrameTime);
1104  int viddelta = frame.timecode - vidTime;
1105  int delta = viddelta - auddelta;
1106  int absdelta = delta < 0 ? -delta : delta;
1107  if (absdelta < 500 && absdelta >= vidFrameTime)
1108  {
1109  QString msg = QString("Audio is %1ms %2 video at # %3: "
1110  "auddelta=%4, viddelta=%5")
1111  .arg(absdelta)
1112  .arg(((delta > 0) ? "ahead of" : "behind"))
1113  .arg((int)curFrameNum)
1114  .arg(auddelta)
1115  .arg(viddelta);
1116  LOG(VB_GENERAL, LOG_INFO, msg);
1117  dropvideo = (delta > 0) ? 1 : -1;
1118  wait_recover = 0;
1119  }
1120  else if (delta >= 500 && delta < 10000)
1121  {
1122  if (wait_recover == 0)
1123  {
1124  dropvideo = 5;
1125  wait_recover = 6;
1126  }
1127  else if (wait_recover == 1)
1128  {
1129  // Video is badly lagging. Try to catch up.
1130  int count = 0;
1131  while (delta > vidFrameTime)
1132  {
1133  if (!cutter || !cutter->InhibitDummyFrame())
1134  m_fifow->FIFOWrite(0, frame.buf, frame.size);
1135 
1136  count++;
1137  delta -= (int)vidFrameTime;
1138  }
1139  QString msg = QString("Added %1 blank video frames")
1140  .arg(count);
1141  LOG(VB_GENERAL, LOG_INFO, msg);
1142  curFrameNum += count;
1143  dropvideo = 0;
1144  wait_recover = 0;
1145  }
1146  else
1147  wait_recover--;
1148  }
1149  else
1150  {
1151  dropvideo = 0;
1152  wait_recover = 0;
1153  }
1154 
1155 #if 0
1156  int buflen = (int)(arb->audiobuffer_len / rateTimeConv);
1157  LOG(VB_GENERAL, LOG_DEBUG,
1158  QString("%1: video time: %2 audio time: %3 "
1159  "buf: %4 exp: %5 delta: %6")
1160  .arg(curFrameNum) .arg(frame.timecode)
1161  .arg(arb->last_audiotime) .arg(buflen) .arg(audbufTime)
1162  .arg(delta));
1163 #endif
1164  AudioBuffer *ab = nullptr;
1165  while ((ab = arb->GetData(frame.timecode)) != nullptr)
1166  {
1167  if (!cutter ||
1168  !cutter->InhibitUseAudioFrames(ab->m_frames, &totalAudio))
1169  m_fifow->FIFOWrite(1, ab->data(), ab->size());
1170 
1171  delete ab;
1172  }
1173 
1174  if (dropvideo < 0)
1175  {
1176  if (cutter && cutter->InhibitDropFrame())
1177  m_fifow->FIFOWrite(0, frame.buf, frame.size);
1178 
1179  LOG(VB_GENERAL, LOG_INFO, "Dropping video frame");
1180  dropvideo++;
1181  curFrameNum--;
1182  }
1183  else
1184  {
1185  if (!cutter || !cutter->InhibitUseVideoFrame())
1186  m_fifow->FIFOWrite(0, frame.buf, frame.size);
1187 
1188  if (dropvideo)
1189  {
1190  if (!cutter || !cutter->InhibitDummyFrame())
1191  m_fifow->FIFOWrite(0, frame.buf, frame.size);
1192 
1193  curFrameNum++;
1194  dropvideo--;
1195  }
1196  }
1197  videoOutput->DoneDisplayingFrame(lastDecode);
1199  lasttimecode = frame.timecode;
1200  }
1201  else if (copyaudio)
1202  {
1203 #if CONFIG_LIBMP3LAME
1204  // Encoding from NuppelVideo to NuppelVideo with MP3 audio
1205  // So let's not decode/reencode audio
1206  if (!GetPlayer()->GetRawAudioState())
1207  {
1208  // The Raw state changed during decode. This is not good
1209  LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, MythPlayer "
1210  "is not in raw audio mode.");
1211 
1212  unlink(outputname.toLocal8Bit().constData());
1213  if (rescale)
1214  {
1215  av_freep(&frame.buf);
1216  }
1217  SetPlayerContext(nullptr);
1218  if (videoBuffer)
1219  videoBuffer->stop();
1220  if (hls)
1221  {
1222  hls->UpdateStatus(kHLSStatusErrored);
1223  hls->UpdateStatusMessage("Transcoding Errored");
1224  }
1225  return REENCODE_ERROR;
1226  }
1227 
1228  if (forceKeyFrames)
1229  writekeyframe = true;
1230  else
1231  {
1232  writekeyframe = is_key;
1233  if (writekeyframe)
1234  {
1235  // Currently, we don't create new sync frames,
1236  // (though we do create new 'I' frames), so we mark
1237  // the key-frames before deciding whether we need a
1238  // new 'I' frame.
1239 
1240  //need to correct the frame# and timecode here
1241  // Question: Is it necessary to change the timecodes?
1242  long sync_offset =
1243  GetPlayer()->UpdateStoredFrameNum(curFrameNum);
1244  m_nvr->UpdateSeekTable(num_keyframes, sync_offset);
1245  ReencoderAddKFA(curFrameNum, lastKeyFrame, num_keyframes);
1246  num_keyframes++;
1247  lastKeyFrame = curFrameNum;
1248 
1249  if (did_ff)
1250  did_ff = 0;
1251  }
1252  }
1253 
1254  if (did_ff == 1)
1255  {
1256  timecodeOffset +=
1257  (frame.timecode - lasttimecode - (int)vidFrameTime);
1258  }
1259  lasttimecode = frame.timecode;
1260 // from here on the timecode is on the output time base
1261  frame.timecode -= timecodeOffset;
1262 
1263  if (!GetPlayer()->WriteStoredData(m_outBuffer, (did_ff == 0), timecodeOffset))
1264  {
1265  if (video_aspect != new_aspect)
1266  {
1267  video_aspect = new_aspect;
1268  m_nvr->SetNewVideoParams(video_aspect);
1269  }
1270 
1271  QSize buf_size3 = GetPlayer()->GetVideoBufferSize();
1272 
1273  if (video_width != buf_size3.width() ||
1274  video_height != buf_size3.height())
1275  {
1276  video_width = buf_size3.width();
1277  video_height = buf_size3.height();
1278 
1279  LOG(VB_GENERAL, LOG_INFO,
1280  QString("Resizing from %1x%2 to %3x%4")
1281  .arg(video_width).arg(video_height)
1282  .arg(newWidth).arg(newHeight));
1283 
1284  }
1285 
1286  if (did_ff == 1)
1287  {
1288  // Create a new 'I' frame if we just processed a cut.
1289  did_ff = 2;
1290  writekeyframe = true;
1291  }
1292 
1293  if (rescale)
1294  {
1295  AVPictureFill(&imageIn, lastDecode);
1296  AVPictureFill(&imageOut, &frame);
1297 
1298  int bottomBand = (lastDecode->height == 1088) ? 8 : 0;
1299  scontext = sws_getCachedContext(scontext,
1300  lastDecode->width, lastDecode->height, FrameTypeToPixelFormat(lastDecode->codec),
1301  frame.width, frame.height, FrameTypeToPixelFormat(frame.codec),
1302  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1303 
1304  sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1305  lastDecode->height - bottomBand,
1306  imageOut.data, imageOut.linesize);
1307  }
1308 
1309  m_nvr->WriteVideo(rescale ? &frame : lastDecode, true, writekeyframe);
1310  }
1312 #else
1313  LOG(VB_GENERAL, LOG_ERR,
1314  "Not compiled with libmp3lame support. Should never get here");
1315  return REENCODE_ERROR;
1316 #endif // CONFIG_LIBMP3LAME
1317  }
1318  else
1319  {
1320  if (did_ff == 1)
1321  {
1322  did_ff = 2;
1323  timecodeOffset +=
1324  (frame.timecode - lasttimecode - (int)vidFrameTime);
1325  }
1326 
1327  if (video_aspect != new_aspect)
1328  {
1329  video_aspect = new_aspect;
1330 #if CONFIG_LIBMP3LAME
1331  if (m_nvr)
1332  m_nvr->SetNewVideoParams(video_aspect);
1333 #endif
1334  }
1335 
1336 
1337  QSize buf_size4 = GetPlayer()->GetVideoBufferSize();
1338 
1339  if (video_width != buf_size4.width() ||
1340  video_height != buf_size4.height())
1341  {
1342  video_width = buf_size4.width();
1343  video_height = buf_size4.height();
1344 
1345  LOG(VB_GENERAL, LOG_INFO,
1346  QString("Resizing from %1x%2 to %3x%4")
1347  .arg(video_width).arg(video_height)
1348  .arg(newWidth).arg(newHeight));
1349  }
1350 
1351  if (rescale)
1352  {
1353  AVPictureFill(&imageIn, lastDecode);
1354  AVPictureFill(&imageOut, &frame);
1355 
1356  int bottomBand = (lastDecode->height == 1088) ? 8 : 0;
1357  scontext = sws_getCachedContext(scontext,
1358  lastDecode->width, lastDecode->height, FrameTypeToPixelFormat(lastDecode->codec),
1359  frame.width, frame.height, FrameTypeToPixelFormat(frame.codec),
1360  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1361 
1362  sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1363  lastDecode->height - bottomBand,
1364  imageOut.data, imageOut.linesize);
1365  }
1366 
1367  // audio is fully decoded, so we need to reencode it
1368  AudioBuffer *ab = nullptr;
1369  while ((ab = arb->GetData(lastWrittenTime)) != nullptr)
1370  {
1371  auto *buf = (unsigned char *)ab->data();
1372  if (m_avfMode)
1373  {
1374  if (did_ff != 1)
1375  {
1376  long long tc = ab->m_time - timecodeOffset;
1377  avfw->WriteAudioFrame(buf, audioFrame, tc);
1378 
1379  if (avfw2)
1380  {
1381  if ((avfw2->GetTimecodeOffset() == -1) &&
1382  (avfw->GetTimecodeOffset() != -1))
1383  {
1384  avfw2->SetTimecodeOffset(
1385  avfw->GetTimecodeOffset());
1386  }
1387 
1388  tc = ab->m_time - timecodeOffset;
1389  avfw2->WriteAudioFrame(buf, audioFrame, tc);
1390  }
1391 
1392  ++audioFrame;
1393  }
1394  }
1395 #if CONFIG_LIBMP3LAME
1396  else
1397  {
1398  m_nvr->SetOption("audioframesize", ab->size());
1399  m_nvr->WriteAudio(buf, audioFrame++,
1400  ab->m_time - timecodeOffset);
1401  if (m_nvr->IsErrored())
1402  {
1403  LOG(VB_GENERAL, LOG_ERR,
1404  "Transcode: Encountered irrecoverable error in "
1405  "NVR::WriteAudio");
1406 
1407  if (rescale)
1408  {
1409  av_freep(&frame.buf);
1410  }
1411  SetPlayerContext(nullptr);
1412  if (videoBuffer)
1413  videoBuffer->stop();
1414  delete ab;
1415  return REENCODE_ERROR;
1416  }
1417  }
1418 #endif
1419  delete ab;
1420  }
1421 
1422  if (!m_avfMode)
1423  {
1424 #if CONFIG_LIBMP3LAME
1425  GetPlayer()->GetCC608Reader()->
1426  TranscodeWriteText(&TranscodeWriteText, (void *)(m_nvr));
1427 #else
1428  LOG(VB_GENERAL, LOG_ERR,
1429  "Not compiled with libmp3lame support");
1430  return REENCODE_ERROR;
1431 #endif
1432  }
1433  lasttimecode = frame.timecode;
1434  frame.timecode -= timecodeOffset;
1435 
1436  if (m_avfMode)
1437  {
1438  if (halfFramerate && !skippedLastFrame)
1439  {
1440  skippedLastFrame = true;
1441  }
1442  else
1443  {
1444  skippedLastFrame = false;
1445 
1446  if ((hls) &&
1447  (avfw->GetFramesWritten()) &&
1448  (hlsSegmentFrames > hlsSegmentSize) &&
1449  (avfw->NextFrameIsKeyFrame()))
1450  {
1451  hls->AddSegment();
1452  avfw->ReOpen(hls->GetCurrentFilename());
1453 
1454  if (avfw2)
1455  avfw2->ReOpen(hls->GetCurrentFilename(true));
1456 
1457  hlsSegmentFrames = 0;
1458  }
1459 
1460  if (avfw->WriteVideoFrame(rescale ? &frame : lastDecode) > 0)
1461  {
1462  lastWrittenTime = frame.timecode + timecodeOffset;
1463  if (hls)
1464  ++hlsSegmentFrames;
1465  }
1466 
1467  }
1468  }
1469 #if CONFIG_LIBMP3LAME
1470  else
1471  {
1472  if (forceKeyFrames)
1473  m_nvr->WriteVideo(rescale ? &frame : lastDecode, true, true);
1474  else
1475  m_nvr->WriteVideo(rescale ? &frame : lastDecode);
1476  lastWrittenTime = frame.timecode + timecodeOffset;
1477  }
1478 #endif
1479  }
1480  if (MythDate::current() > statustime)
1481  {
1482  if (m_showProgress)
1483  {
1484  LOG(VB_GENERAL, LOG_INFO,
1485  QString("Processed: %1 of %2 frames(%3 seconds)").
1486  arg(curFrameNum).arg((long)total_frame_count).
1487  arg((long)(curFrameNum / video_frame_rate)));
1488  }
1489 
1490  if (hls && hls->CheckStop())
1491  {
1492  hls->UpdateStatus(kHLSStatusStopping);
1493  stopSignalled = true;
1494  }
1495 
1496  statustime = MythDate::current().addSecs(5);
1497  }
1498  if (MythDate::current() > curtime)
1499  {
1500  if (honorCutList && m_proginfo && !m_avfMode &&
1502  {
1503  LOG(VB_GENERAL, LOG_NOTICE,
1504  "Transcoding aborted, cutlist updated");
1505 
1506  unlink(outputname.toLocal8Bit().constData());
1507  if (rescale)
1508  {
1509  av_freep(&frame.buf);
1510  }
1511  SetPlayerContext(nullptr);
1512  if (videoBuffer)
1513  videoBuffer->stop();
1514  return REENCODE_CUTLIST_CHANGE;
1515  }
1516 
1517  if ((jobID >= 0) || (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_INFO)))
1518  {
1520  {
1521  LOG(VB_GENERAL, LOG_NOTICE,
1522  "Transcoding STOPped by JobQueue");
1523 
1524  unlink(outputname.toLocal8Bit().constData());
1525  if (rescale)
1526  {
1527  av_freep(&frame.buf);
1528  }
1529  SetPlayerContext(nullptr);
1530  if (videoBuffer)
1531  videoBuffer->stop();
1532  if (hls)
1533  {
1534  hls->UpdateStatus(kHLSStatusStopped);
1535  hls->UpdateStatusMessage("Transcoding Stopped");
1536  }
1537  return REENCODE_STOPPED;
1538  }
1539 
1540  float flagFPS = 0.0;
1541  float elapsed = flagTime.elapsed() / 1000.0;
1542  if (elapsed != 0.0F)
1543  flagFPS = curFrameNum / elapsed;
1544 
1545  total_frame_count = GetPlayer()->GetCurrentFrameCount();
1546  int percentage = curFrameNum * 100 / total_frame_count;
1547 
1548  if (hls)
1549  hls->UpdatePercentComplete(percentage);
1550 
1551  if (jobID >= 0)
1552  {
1554  QObject::tr("%1% Completed @ %2 fps.")
1555  .arg(percentage).arg(flagFPS));
1556  }
1557  else
1558  {
1559  LOG(VB_GENERAL, LOG_INFO,
1560  QString("mythtranscode: %1% Completed @ %2 fps.")
1561  .arg(percentage).arg(flagFPS));
1562  }
1563 
1564  }
1565  curtime = MythDate::current().addSecs(20);
1566  }
1567 
1568  curFrameNum++;
1569  frame.frameNumber = 1 + (curFrameNum << 1);
1570 
1571  GetPlayer()->DiscardVideoFrame(lastDecode);
1572  }
1573 
1574  sws_freeContext(scontext);
1575 
1576  if (!m_fifow)
1577  {
1578  if (avfw)
1579  avfw->CloseFile();
1580 
1581  if (avfw2)
1582  avfw2->CloseFile();
1583 
1584  if (!m_avfMode && m_proginfo)
1585  {
1590  }
1591 
1592 #if CONFIG_LIBMP3LAME
1593  if (m_nvr)
1594  {
1595  m_nvr->WriteSeekTable();
1596  if (!m_kfaTable->empty())
1597  m_nvr->WriteKeyFrameAdjustTable(*m_kfaTable);
1598  }
1599 #endif // CONFIG_LIBMP3LAME
1600  } else {
1601  m_fifow->FIFODrain();
1602  }
1603 
1604  if (hls)
1605  {
1606  if (!stopSignalled)
1607  {
1608  hls->UpdateStatus(kHLSStatusCompleted);
1609  hls->UpdateStatusMessage("Transcoding Completed");
1610  hls->UpdatePercentComplete(100);
1611  }
1612  else
1613  {
1614  hls->UpdateStatus(kHLSStatusStopped);
1615  hls->UpdateStatusMessage("Transcoding Stopped");
1616  }
1617  }
1618 
1619  if (videoBuffer)
1620  {
1621  videoBuffer->stop();
1622  }
1623 
1624  if (rescale)
1625  {
1626  av_freep(&frame.buf);
1627  }
1628  SetPlayerContext(nullptr);
1629 
1630  return REENCODE_OK;
1631 }
1632 
1633 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1634 
JobQueue::GetJobCmd
static enum JobCmds GetJobCmd(int jobID)
Definition: jobqueue.cpp:1463
FORMAT_NONE
@ FORMAT_NONE
Definition: audiooutputsettings.h:26
MARK_KEYFRAME
@ MARK_KEYFRAME
Definition: programtypes.h:62
DecoderBase::SetTrack
virtual int SetTrack(uint Type, int TrackNo)
Definition: decoderbase.cpp:962
Transcode::m_cmdContainer
QString m_cmdContainer
Definition: transcode.h:67
DEINT_MEDIUM
@ DEINT_MEDIUM
Definition: mythframe.h:125
RemoteGetExistingRecorder
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)
Definition: tvremoteutil.cpp:313
MythPlayer::GetVideoOutput
MythVideoOutput * GetVideoOutput(void)
Definition: mythplayer.h:281
MythPlayer::GetTotalFrameCount
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:236
MythVideoOutput
Definition: mythvideoout.h:37
deletemap.h
GetBufferSize
static size_t GetBufferSize(VideoFrameType Type, int Width, int Height, int Aligned=MYTH_WIDTH_ALIGNMENT)
Definition: mythframe.h:658
FORMAT_S16
@ FORMAT_S16
Definition: audiooutputsettings.h:28
MythPlayer::SetTranscoding
void SetTranscoding(bool value)
Definition: mythplayer.cpp:3438
Transcode::m_fifow
MythFIFOWriter * m_fifow
Definition: transcode.h:58
Transcode::GetPlayerContext
PlayerContext * GetPlayerContext(void)
Definition: transcode.h:46
AudioReencodeBuffer
This class is to act as a fake audio output device to store the data for reencoding.
Definition: audioreencodebuffer.h:32
AudioPlayer
Definition: audioplayer.h:27
AudioPlayer::ReinitAudio
QString ReinitAudio(void)
Definition: audioplayer.cpp:104
Transcode::m_outBuffer
MythMediaBuffer * m_outBuffer
Definition: transcode.h:57
AudioReencodeBuffer::m_eff_audiorate
int m_eff_audiorate
Definition: audioreencodebuffer.h:72
MythPlayer::TranscodeGetNextFrame
bool TranscodeGetNextFrame(int &did_ff, bool &is_key, bool honorCutList)
Definition: mythplayer.cpp:4713
NuppelVideoRecorder.h
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, int Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:104
Transcode::m_keyframeDist
int m_keyframeDist
Definition: transcode.h:52
RecordingProfile::loadByGroup
virtual bool loadByGroup(const QString &name, const QString &group)
Definition: recordingprofile.cpp:1545
VideoFrame::timecode
long long timecode
Definition: mythframe.h:150
Transcode::m_recProfile
RecordingProfile * m_recProfile
Definition: transcode.h:51
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:75
cutter.h
MythVideoOutput::DoneDisplayingFrame
virtual void DoneDisplayingFrame(VideoFrame *Frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
Definition: mythvideoout.cpp:907
Transcode::Transcode
Transcode(ProgramInfo *pginfo)
Definition: transcode.cpp:52
arg
arg(title).arg(filename).arg(doDelete))
mythdbcon.h
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:82
kfatable_entry::keyframe_number
int keyframe_number
Definition: format.h:132
Transcode::m_cmdAudioBitrate
int m_cmdAudioBitrate
Definition: transcode.h:73
MythMediaBuffer
Definition: mythmediabuffer.h:50
RecordingProfile::loadByID
virtual void loadByID(int id)
Definition: recordingprofile.cpp:1449
MythPlayer::GetFrameRate
float GetFrameRate(void) const
Definition: mythplayer.h:219
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythPlayer::GetCurrentFrameCount
uint64_t GetCurrentFrameCount(void) const
Definition: mythplayer.cpp:4873
MythFIFOWriter
Definition: mythfifowriter.h:34
httplivestream.h
mythplayer.h
JOB_STOP
@ JOB_STOP
Definition: jobqueue.h:50
PlayerFlags
PlayerFlags
Definition: mythplayer.h:88
MythPlayer
Definition: mythplayer.h:165
VideoFrame
Definition: mythframe.h:138
kfatable_entry
Definition: format.h:130
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:407
Transcode::m_cmdHeight
int m_cmdHeight
Definition: transcode.h:71
Transcode::m_hlsStreamID
int m_hlsStreamID
Definition: transcode.h:64
MythPlayer::SetPlayerInfo
void SetPlayerInfo(TV *tv, QWidget *widget, PlayerContext *ctx)
Definition: mythplayer.cpp:4054
MythPlayer::WriteStoredData
bool WriteStoredData(MythMediaBuffer *OutBuffer, bool WriteVideo, long TimecodeOffset)
Definition: mythplayer.cpp:4787
MythFIFOWriter::FIFODrain
void FIFODrain(void)
Definition: mythfifowriter.cpp:255
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
JobQueue::IsJobRunning
static bool IsJobRunning(int jobType, uint chanid, const QDateTime &recstartts)
Definition: jobqueue.cpp:1093
MythPlayer::GetEncodingType
QString GetEncodingType(void) const
Definition: mythplayer.cpp:4632
VideoFrame::codec
VideoFrameType codec
Definition: mythframe.h:139
AudioReencodeBuffer::GetSamples
long long GetSamples(long long time)
Definition: audioreencodebuffer.cpp:221
kHLSStatusStarting
@ kHLSStatusStarting
Definition: httplivestream.h:13
Transcode::m_hlsDisableAudioOnly
bool m_hlsDisableAudioOnly
Definition: transcode.h:65
MythPlayer::GetRawAudioState
bool GetRawAudioState(void) const
Definition: mythplayer.cpp:4671
DEINT_CPU
@ DEINT_CPU
Definition: mythframe.h:127
MythPlayer::UpdateStoredFrameNum
long UpdateStoredFrameNum(long curFrameNum)
Definition: mythplayer.cpp:4775
Transcode::m_hlsMaxSegments
int m_hlsMaxSegments
Definition: transcode.h:66
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
MythPlayer::DiscardVideoFrame
void DiscardVideoFrame(VideoFrame *buffer)
Places frame in the available frames queue.
Definition: mythplayer.cpp:996
AudioOutput
Definition: audiooutput.h:26
kHLSStatusStopped
@ kHLSStatusStopped
Definition: httplivestream.h:18
programinfo.h
ProgramInfo::QueryMarkupFlag
bool QueryMarkupFlag(MarkTypes type) const
Returns true iff the speficied mark type is set on frame 0.
Definition: programinfo.cpp:3572
Transcode::m_cmdVideoCodec
QString m_cmdVideoCodec
Definition: transcode.h:69
Transcode::GetPlayer
MythPlayer * GetPlayer(void)
Definition: transcode.h:47
hardwareprofile.scan.profile
profile
Definition: scan.py:99
kHLSStatusCompleted
@ kHLSStatusCompleted
Definition: httplivestream.h:15
AudioReencodeBuffer::m_bytes_per_frame
int m_bytes_per_frame
Definition: audioreencodebuffer.h:71
MythPlayer::GetVideoBufferSize
QSize GetVideoBufferSize(void) const
Definition: mythplayer.h:216
MARK_DURATION_MS
@ MARK_DURATION_MS
Definition: programtypes.h:74
JobQueue::ChangeJobComment
static bool ChangeJobComment(int jobID, const QString &comment="")
Definition: jobqueue.cpp:1017
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:28
MARK_GOP_START
@ MARK_GOP_START
Definition: programtypes.h:61
CC608Reader::FlushTxtBuffers
void FlushTxtBuffers(void)
Definition: cc608reader.cpp:30
Transcode::m_cmdAudioCodec
QString m_cmdAudioCodec
Definition: transcode.h:68
MythPlayer::GetCC608Reader
virtual CC608Reader * GetCC608Reader(uint=0)
Definition: mythplayer.h:330
VideoFrame::aspect
float aspect
Definition: mythframe.h:144
ProgramInfo::QueryCutList
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
Definition: programinfo.cpp:3291
REENCODE_OK
#define REENCODE_OK
Definition: transcodedefs.h:6
MythFIFOWriter::FIFOInit
bool FIFOInit(uint Id, const QString &Desc, const QString &Name, long Size, int NumBufs)
Definition: mythfifowriter.cpp:109
AudioReencodeBuffer::m_audioFrameSize
int m_audioFrameSize
Definition: audioreencodebuffer.h:75
AudioBuffer::size
int size(void) const
Definition: audioreencodebuffer.h:18
ProgramInfo::ClearMarkupFlag
void ClearMarkupFlag(MarkTypes type) const
Definition: programinfo.h:626
hardwareprofile.smolt.long
long
Definition: smolt.py:76
jobqueue.h
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:51
AudioBuffer::data
char * data(void) const
Definition: audioreencodebuffer.h:17
kTrackTypeAudio
@ kTrackTypeAudio
Definition: decoderbase.h:28
mythavformatwriter.h
kNoITV
@ kNoITV
Definition: mythplayer.h:100
init
static void init(VideoFrame *vf, VideoFrameType _codec, unsigned char *_buf, int _width, int _height, int _size, const int *p=nullptr, const int *o=nullptr, float _aspect=-1.0F, double _rate=-1.0F, int _aligned=MYTH_WIDTH_ALIGNMENT)
Definition: mythframe.h:232
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
kHLSStatusStopping
@ kHLSStatusStopping
Definition: httplivestream.h:17
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:930
Transcode::m_cmdBitrate
int m_cmdBitrate
Definition: transcode.h:72
kTranscoderInUseID
const char * kTranscoderInUseID
Definition: programtypes.cpp:21
MythPlayer::GetDecoder
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:313
MythFIFOWriter::FIFOWrite
void FIFOWrite(uint Id, void *Buffer, long Size)
Definition: mythfifowriter.cpp:210
Transcode::GetProfile
bool GetProfile(const QString &profileName, const QString &encodingType, int height, int frameRate)
Definition: transcode.cpp:81
tvremoteutil.h
AudioBuffer::m_time
long long m_time
Definition: audioreencodebuffer.h:24
DecoderBase::GetVideoAspect
float GetVideoAspect(void) const
Definition: decoderbase.h:183
AudioPlayer::SetAudioOutput
void SetAudioOutput(AudioOutput *ao)
Definition: audioplayer.cpp:209
Transcode::m_recorderOptions
QString m_recorderOptions
Definition: transcode.h:61
Transcode::m_proginfo
ProgramInfo * m_proginfo
Definition: transcode.h:50
mthreadpool.h
AudioBuffer::m_frames
int m_frames
Definition: audioreencodebuffer.h:23
MythPlayer::GetAudio
AudioPlayer * GetAudio(void)
Definition: mythplayer.h:231
MythPlayer::InitForTranscode
void InitForTranscode(bool copyaudio, bool copyvideo)
Definition: mythplayer.cpp:4685
kVideoIsNull
@ kVideoIsNull
Definition: mythplayer.h:98
MythPlayer::SetWatchingRecording
void SetWatchingRecording(bool mode)
Definition: mythplayer.cpp:214
Transcode::m_avfMode
bool m_avfMode
Definition: transcode.h:62
VERBOSE_LEVEL_CHECK
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:14
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:68
MythPlayer::ForceDeinterlacer
void ForceDeinterlacer(bool DoubleRate, MythDeintType Deinterlacer)
Definition: mythplayer.cpp:2215
AudioPlayer::GetCodec
AVCodecID GetCodec(void) const
Definition: audioplayer.h:59
AVPictureFill
int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
AVPictureFill Initialise AVFrame pic with content from VideoFrame frame.
Definition: mythavutil.cpp:197
kHLSStatusErrored
@ kHLSStatusErrored
Definition: httplivestream.h:16
VideoDecodeBuffer
Definition: videodecodebuffer.h:15
mythcorecontext.h
Transcode::m_kfaTable
KFATable * m_kfaTable
Definition: transcode.h:59
transcode.h
MARK_GOP_BYFRAME
@ MARK_GOP_BYFRAME
Definition: programtypes.h:64
MARK_UPDATED_CUT
@ MARK_UPDATED_CUT
Definition: programtypes.h:53
ProgramInfo::QueryIsEditing
bool QueryIsEditing(void) const
Queries "recorded" table for its "editing" field and returns true if it is set to true.
Definition: programinfo.cpp:2927
ProgramInfo::ClearPositionMap
void ClearPositionMap(MarkTypes type) const
Definition: programinfo.cpp:3636
AudioReencodeBuffer::m_passthru
bool m_passthru
Definition: audioreencodebuffer.h:74
audiooutput.h
Transcode::~Transcode
~Transcode() override
Definition: transcode.cpp:58
mythavutil.h
MythPlayer::GetVideoAspect
float GetVideoAspect(void) const
Definition: mythplayer.h:218
AudioReencodeBuffer::GetData
AudioBuffer * GetData(long long time)
Definition: audioreencodebuffer.cpp:203
Transcode::m_hlsMode
bool m_hlsMode
Definition: transcode.h:63
VideoFrame::height
int height
Definition: mythframe.h:143
VideoFrame::frameNumber
long long frameNumber
Definition: mythframe.h:148
PlayerContext
Definition: playercontext.h:49
MythMediaBuffer::GetLastError
QString GetLastError(void) const
Definition: mythmediabuffer.cpp:1769
AudioBuffer
Definition: audioreencodebuffer.h:10
videodecodebuffer.h
audioreencodebuffer.h
REENCODE_CUTLIST_CHANGE
#define REENCODE_CUTLIST_CHANGE
Definition: transcodedefs.h:5
Transcode::m_ctx
PlayerContext * m_ctx
Definition: transcode.h:56
StandardSetting
Definition: standardsettings.h:30
MythPlayer::SetCutList
void SetCutList(const frm_dir_map_t &newCutList)
Definition: mythplayer.cpp:4782
REENCODE_ERROR
#define REENCODE_ERROR
Definition: transcodedefs.h:7
recordingprofile.h
Transcode::m_showProgress
bool m_showProgress
Definition: transcode.h:60
RecordingProfile
Definition: recordingprofile.h:40
LOC
#define LOC
Definition: transcode.cpp:50
round
#define round(x)
Definition: mythplayer.cpp:64
REENCODE_MPEG2TRANS
#define REENCODE_MPEG2TRANS
Definition: transcodedefs.h:4
exitcodes.h
jobID
int jobID
Definition: mythtv/programs/mythcommflag/main.cpp:85
Transcode::SetPlayerContext
void SetPlayerContext(PlayerContext *player_ctx)
Definition: transcode.cpp:142
Transcode::m_cmdWidth
int m_cmdWidth
Definition: transcode.h:70
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:307
kHLSStatusRunning
@ kHLSStatusRunning
Definition: httplivestream.h:14
GetAlignedBuffer
static unsigned char * GetAlignedBuffer(size_t Size)
Definition: mythframe.h:679
build_compdb.options
options
Definition: build_compdb.py:11
Transcode::ReencoderAddKFA
void ReencoderAddKFA(long curframe, long lastkey, long num_keyframes)
Definition: transcode.cpp:69
AudioReencodeBuffer::m_channels
int m_channels
Definition: audioreencodebuffer.h:70
kfatable_entry::adjust
int adjust
Definition: format.h:131
VideoFrame::width
int width
Definition: mythframe.h:142
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:342
DecoderBase
Definition: decoderbase.h:120
FrameTypeToPixelFormat
AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type)
Convert VideoFrameType into FFmpeg's PixelFormat equivalent and vice-versa.
Definition: mythavutil.cpp:25
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:916
REENCODE_STOPPED
#define REENCODE_STOPPED
Definition: transcodedefs.h:8
NuppelVideoRecorder
Definition: NuppelVideoRecorder.h:73
Transcode::TranscodeFile
int TranscodeFile(const QString &inputname, const QString &outputname, const QString &profileName, bool honorCutList, bool framecontrol, int jobID, const QString &fifodir, bool fifo_info, bool cleanCut, frm_dir_map_t &deleteMap, int AudioTrackNo, bool passthru=false)
Definition: transcode.cpp:195