10 #include <QWaitCondition>
12 #include <QMutexLocker>
13 #include <QtAlgorithms>
15 #include "mythconfig.h"
41 #include "libavcodec/avcodec.h"
42 #include "libswscale/swscale.h"
48 #define LOC QString("Transcode: ")
69 long delta = curframe - lastkey;
80 int height,
int frameRate)
82 if (profileName.toLower() ==
"autodetect")
87 QString autoProfileName = QObject::tr(
"Autodetect from %1").arg(height);
88 if (frameRate == 25 || frameRate == 30)
89 autoProfileName +=
"i";
90 if (frameRate == 50 || frameRate == 60)
91 autoProfileName +=
"p";
94 LOG(VB_GENERAL, LOG_NOTICE,
95 QString(
"Transcode: Looking for autodetect profile: %1")
96 .
arg(autoProfileName));
99 if (!result && encodingType ==
"MPEG-2")
102 autoProfileName =
"MPEG2";
104 if (!result && (encodingType ==
"MPEG-4" || encodingType ==
"RTjpeg"))
108 autoProfileName =
"RTjpeg/MPEG4";
112 LOG(VB_GENERAL, LOG_ERR,
113 QString(
"Transcode: Couldn't find profile for : %1")
119 LOG(VB_GENERAL, LOG_NOTICE,
120 QString(
"Transcode: Using autodetect profile: %1")
121 .
arg(autoProfileName));
126 int profileID = profileName.toInt(&isNum);
128 if (isNum && profileID > 0)
132 LOG(VB_GENERAL, LOG_ERR, QString(
"Couldn't find profile #: %1")
142 if (player_ctx ==
m_ctx)
149 #if CONFIG_LIBMP3LAME
156 LOG(VB_GENERAL, LOG_ERR,
LOC +
157 QString(
"get_str_option(...%1): Option not in profile.").
arg(name));
164 QString ret_str = get_str_option(
profile, name);
165 if (ret_str.isEmpty())
169 int ret_int = ret_str.toInt(&ok);
173 LOG(VB_GENERAL, LOG_ERR,
LOC +
174 QString(
"get_int_option(...%1): Option is not an int.").
arg(name));
182 return get_int_option(
profile, name) != 0;
185 static void TranscodeWriteText(
void *ptr,
unsigned char *buf,
int len,
186 std::chrono::milliseconds timecode,
int pagenr)
189 nvr->WriteText(buf, len, timecode, pagenr);
191 #endif // CONFIG_LIBMP3LAME
194 const QString &outputname,
195 const QString &profileName,
196 bool honorCutList,
bool framecontrol,
197 int jobID,
const QString& fifodir,
198 bool fifo_info,
bool cleanCut,
204 QDateTime statustime = curtime;
206 std::unique_ptr<Cutter> cutter =
nullptr;
207 std::unique_ptr<MythAVFormatWriter> avfw =
nullptr;
208 std::unique_ptr<MythAVFormatWriter> avfw2 =
nullptr;
209 std::unique_ptr<HTTPLiveStream> hls =
nullptr;
210 int hlsSegmentSize = 0;
211 int hlsSegmentFrames = 0;
213 #if !CONFIG_LIBMP3LAME
228 hls->UpdateStatusMessage(
"Transcoding Starting");
238 #if CONFIG_LIBMP3LAME
241 LOG(VB_GENERAL, LOG_ERR,
242 "Not compiled with libmp3lame support");
255 LOG(VB_GENERAL, LOG_ERR,
256 QString(
"Transcoding aborted, error: '%1'")
261 player_ctx->SetRingBuffer(rb);
265 if (player ==
nullptr)
267 LOG(VB_GENERAL, LOG_ERR,
268 QString(
"Transcoding aborted, failed to retrieve MythPlayer object"));
274 player->SetWatchingRecording(
true);
279 statustime = statustime.addSecs(5);
285 player->GetAudio()->SetAudioOutput(audioOutput);
286 player->SetTranscoding(
true);
288 if (player->OpenFile() < 0)
290 LOG(VB_GENERAL, LOG_ERR,
"Transcoding aborted, error opening file.");
295 if (AudioTrackNo > -1)
297 LOG(VB_GENERAL, LOG_INFO,
298 QString(
"Set audiotrack number to %1").
arg(AudioTrackNo));
302 long long total_frame_count = player->GetTotalFrameCount();
303 long long new_frame_count = total_frame_count;
306 LOG(VB_GENERAL, LOG_INFO,
"Honoring the cutlist while transcoding");
308 frm_dir_map_t::const_iterator it;
310 long long lastStart = 0;
312 if (deleteMap.empty())
315 for (it = deleteMap.cbegin(); it != deleteMap.cend(); ++it)
319 if (!cutStr.isEmpty())
321 cutStr += QString(
"%1-").arg((
long)it.key());
322 lastStart = it.key();
326 if (cutStr.isEmpty())
328 cutStr += QString(
"%1").arg((
long)it.key());
329 new_frame_count -= (it.key() - lastStart);
332 if (cutStr.isEmpty())
334 else if (cutStr.endsWith(
'-') && (total_frame_count > lastStart))
336 new_frame_count -= (total_frame_count - lastStart);
337 cutStr += QString(
"%1").arg(total_frame_count);
339 LOG(VB_GENERAL, LOG_INFO, QString(
"Cutlist : %1").
arg(cutStr));
340 LOG(VB_GENERAL, LOG_INFO, QString(
"Original Length: %1 frames")
341 .
arg((
long)total_frame_count));
342 LOG(VB_GENERAL, LOG_INFO, QString(
"New Length : %1 frames")
343 .
arg((
long)new_frame_count));
348 LOG(VB_GENERAL, LOG_INFO,
"Transcoding aborted, cutlist changed");
353 curtime = curtime.addSecs(60);
356 player->GetAudio()->ReinitAudio();
357 QString encodingType = player->GetEncodingType();
358 bool copyvideo =
false;
359 bool copyaudio =
false;
361 QString vidsetting =
nullptr;
362 QString audsetting =
nullptr;
363 QString vidfilters =
nullptr;
365 QSize buf_size = player->GetVideoBufferSize();
366 int video_width = buf_size.width();
367 int video_height = buf_size.height();
369 if (video_height == 1088) {
370 LOG(VB_GENERAL, LOG_NOTICE,
371 "Found video height of 1088. This is unusual and "
372 "more than likely the video is actually 1080 so mythtranscode "
373 "will treat it as such.");
378 float video_frame_rate = player->GetFrameRate();
379 int newWidth = video_width;
380 int newHeight = video_height;
381 bool halfFramerate =
false;
382 bool skippedLastFrame =
false;
384 m_kfaTable =
new std::vector<struct kfatable_entry>;
402 if (newHeight > video_height)
404 newHeight = video_height;
414 if (newHeight == 0 && newWidth > 0)
415 newHeight = (int)(1.0F * newWidth / video_aspect);
416 else if (newWidth == 0 && newHeight > 0)
417 newWidth = (int)(1.0F * newHeight * video_aspect);
418 else if (newWidth == 0 && newHeight == 0)
421 newWidth = (int)(1.0F * 480 * video_aspect);
425 newHeight = (int)(1.0F * 640 / video_aspect);
430 newHeight = (newHeight + 15) & ~0xF;
431 newWidth = (newWidth + 15) & ~0xF;
433 avfw = std::make_unique<MythAVFormatWriter>();
436 LOG(VB_GENERAL, LOG_ERR,
437 "Transcoding aborted, error creating AVFormatWriter.");
443 avfw->SetHeight(newHeight);
444 avfw->SetWidth(newWidth);
445 avfw->SetAspect(video_aspect);
456 hls = std::make_unique<HTTPLiveStream>(inputname, newWidth, newHeight,
463 LOG(VB_GENERAL, LOG_ERR,
"Unable to create new stream");
469 int segmentSize = hls->GetSegmentSize();
471 LOG(VB_GENERAL, LOG_NOTICE,
472 QString(
"HLS: Using segment size of %1 seconds")
477 int audioOnlyBitrate = hls->GetAudioOnlyBitrate();
479 avfw2 = std::make_unique<MythAVFormatWriter>();
480 avfw2->SetContainer(
"mpegts");
481 avfw2->SetAudioCodec(
"aac");
482 avfw2->SetAudioBitrate(audioOnlyBitrate);
488 avfw->SetContainer(
"mpegts");
489 avfw->SetVideoCodec(
"libx264");
490 avfw->SetAudioCodec(
"aac");
492 hls->UpdateStatusMessage(
"Transcoding Starting");
493 hls->UpdateSizeInfo(newWidth, newHeight, video_width, video_height);
495 if (!hls->InitForWrite())
497 LOG(VB_GENERAL, LOG_ERR,
"hls->InitForWrite() failed");
502 if (video_frame_rate > 30)
504 halfFramerate =
true;
505 avfw->SetFramerate(video_frame_rate/2);
508 avfw2->SetFramerate(video_frame_rate/2);
510 hlsSegmentSize = (int)(segmentSize * video_frame_rate / 2);
514 avfw->SetFramerate(video_frame_rate);
517 avfw2->SetFramerate(video_frame_rate);
519 hlsSegmentSize = (int)(segmentSize * video_frame_rate);
522 avfw->SetKeyFrameDist(30);
524 avfw2->SetKeyFrameDist(30);
527 avfw->SetFilename(hls->GetCurrentFilename());
529 avfw2->SetFilename(hls->GetCurrentFilename(
true));
536 avfw->SetFilename(outputname);
537 avfw->SetFramerate(video_frame_rate);
538 avfw->SetKeyFrameDist(30);
545 LOG(VB_GENERAL, LOG_NOTICE,
546 QString(
"x264 HLS using: %1 threads, '%2' profile and '%3' tune")
549 avfw->SetThreadCount(threads);
550 avfw->SetEncodingPreset(preset);
551 avfw->SetEncodingTune(tune);
554 avfw2->SetThreadCount(1);
558 LOG(VB_GENERAL, LOG_ERR,
"avfw->Init() failed");
563 if (!avfw->OpenFile())
565 LOG(VB_GENERAL, LOG_ERR,
"avfw->OpenFile() failed");
570 if (avfw2 && !avfw2->Init())
572 LOG(VB_GENERAL, LOG_ERR,
"avfw2->Init() failed");
577 if (avfw2 && !avfw2->OpenFile())
579 LOG(VB_GENERAL, LOG_ERR,
"avfw2->OpenFile() failed");
586 #if CONFIG_LIBMP3LAME
587 else if (fifodir.isEmpty())
589 if (!
GetProfile(profileName, encodingType, video_height,
590 (
int)
round(video_frame_rate))) {
591 LOG(VB_GENERAL, LOG_ERR,
"Transcoding aborted, no profile found.");
597 QMap<QString, QString> recorderOptionsMap;
600 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
602 .split(
",", QString::SkipEmptyParts);
605 .split(
",", Qt::SkipEmptyParts);
610 QStringList tokens =
options[loop].split(
"=");
611 if (tokens.length() < 2)
613 LOG(VB_GENERAL, LOG_ERR,
"Transcoding aborted, invalid option settings.");
616 recorderOptionsMap[tokens[0]] = tokens[1];
622 vidsetting = get_str_option(
m_recProfile,
"videocodec");
623 audsetting = get_str_option(
m_recProfile,
"audiocodec");
624 vidfilters = get_str_option(
m_recProfile,
"transcodefilters");
626 if (encodingType ==
"MPEG-2" &&
629 LOG(VB_GENERAL, LOG_NOTICE,
"Switching to MPEG-2 transcoder.");
637 vidsetting = encodingType;
640 else if (get_bool_option(
m_recProfile,
"transcoderesize"))
642 int actualHeight = (video_height == 1088 ? 1080 : video_height);
649 if (newHeight == 0 && newWidth > 0)
650 newHeight = (int)(1.0 * newWidth * actualHeight / video_width);
651 else if (newWidth == 0 && newHeight > 0)
652 newWidth = (int)(1.0 * newHeight * video_width / actualHeight);
653 else if (newWidth == 0 && newHeight == 0)
656 newWidth = (int)(1.0 * 480 * video_width / actualHeight);
660 newHeight = (int)(1.0 * 640 * actualHeight / video_width);
664 if (encodingType.startsWith(
"mpeg", Qt::CaseInsensitive))
667 newHeight = (newHeight + 15) & ~0xF;
668 newWidth = (newWidth + 15) & ~0xF;
671 LOG(VB_GENERAL, LOG_INFO, QString(
"Resizing from %1x%2 to %3x%4")
672 .
arg(video_width).
arg(video_height)
673 .
arg(newWidth).
arg(newHeight));
681 m_nvr->SetOption(
"inpixfmt",
FMT_YV12);
683 m_nvr->SetOption(
"width", newWidth);
684 m_nvr->SetOption(
"height", newHeight);
689 m_nvr->SetFrameRate(video_frame_rate);
690 m_nvr->SetVideoAspect(video_aspect);
691 m_nvr->SetTranscoding(
true);
693 if ((vidsetting ==
"MPEG-4") ||
694 (recorderOptionsMap[
"videocodec"] ==
"mpeg4"))
696 m_nvr->SetOption(
"videocodec",
"mpeg4");
705 #ifdef USING_FFMPEG_THREADS
706 m_nvr->SetIntOption(
m_recProfile,
"encodingthreadcount");
709 else if ((vidsetting ==
"MPEG-2") ||
710 (recorderOptionsMap[
"videocodec"] ==
"mpeg2video"))
712 m_nvr->SetOption(
"videocodec",
"mpeg2video");
716 #ifdef USING_FFMPEG_THREADS
717 m_nvr->SetIntOption(
m_recProfile,
"encodingthreadcount");
720 else if ((vidsetting ==
"RTjpeg") ||
721 (recorderOptionsMap[
"videocodec"] ==
"rtjpeg"))
723 m_nvr->SetOption(
"videocodec",
"rtjpeg");
725 m_nvr->SetIntOption(
m_recProfile,
"rtjpegchromafilter");
728 else if (vidsetting.isEmpty())
730 LOG(VB_GENERAL, LOG_ERR,
"No video information found!");
731 LOG(VB_GENERAL, LOG_ERR,
"Please ensure that recording profiles "
732 "for the transcoder are set");
738 LOG(VB_GENERAL, LOG_ERR,
739 QString(
"Unknown video codec: %1").
arg(vidsetting));
745 if (audsetting ==
"MP3")
747 m_nvr->SetOption(
"audiocompression", 1);
751 else if (audsetting ==
"Uncompressed")
753 m_nvr->SetOption(
"audiocompression", 0);
757 LOG(VB_GENERAL, LOG_ERR,
758 QString(
"Unknown audio codec: %1").
arg(audsetting));
761 m_nvr->AudioInit(
true);
764 if (!recorderOptionsMap.empty())
766 QMap<QString, QString>::Iterator it;
769 for (it = recorderOptionsMap.begin();
770 it != recorderOptionsMap.end(); ++it)
775 LOG(VB_GENERAL, LOG_NOTICE,
776 QString(
"Forcing Recorder option '%1' to '%2'")
779 if (value.contains(QRegExp(
"[^0-9]")))
780 m_nvr->SetOption(key, value);
782 m_nvr->SetOption(key, value.toInt());
785 newWidth = (value.toInt() + 15) & ~0xF;
786 else if (key ==
"height")
787 newHeight = (value.toInt() + 15) & ~0xF;
788 else if (key ==
"videocodec")
790 if (value ==
"mpeg4")
791 vidsetting =
"MPEG-4";
792 else if (value ==
"mpeg2video")
793 vidsetting =
"MPEG-2";
794 else if (value ==
"rtjpeg")
795 vidsetting =
"RTjpeg";
800 if ((vidsetting ==
"MPEG-4") ||
801 (vidsetting ==
"MPEG-2"))
802 m_nvr->SetupAVCodecVideo();
803 else if (vidsetting ==
"RTjpeg")
804 m_nvr->SetupRTjpeg();
808 m_nvr->WriteHeader();
809 m_nvr->StreamAllocate();
812 if (vidsetting == encodingType && !framecontrol && !
m_avfMode &&
813 fifodir.isEmpty() && honorCutList &&
814 video_width == newWidth && video_height == newHeight)
817 LOG(VB_GENERAL, LOG_INFO,
"Reencoding video in 'raw' mode");
819 #endif // CONFIG_LIBMP3LAME
821 if (honorCutList && !deleteMap.empty())
828 cutter = std::make_unique<Cutter>();
829 cutter->SetCutList(deleteMap,
m_ctx);
830 player->SetCutList(cutter->AdjustedCutList());
835 player->SetCutList(deleteMap);
839 player->InitForTranscode(copyaudio, copyvideo);
840 if (player->IsErrored())
842 LOG(VB_GENERAL, LOG_ERR,
843 "Unable to initialize MythPlayer for Transcode");
849 if (
m_hlsMode && player->GetVideoOutput())
856 bool nonAligned = vidsetting ==
"RTjpeg" || !fifodir.isEmpty();
857 bool rescale = (video_width != newWidth) || (video_height != newHeight) || nonAligned;
868 video_width, video_height == 1080 ? 1088 : video_height, 0 );
872 frame.
Init(
FMT_YV12, newbuffer, newSize, video_width, video_height,
nullptr, 0);
880 if (!fifodir.isEmpty())
883 const char *audio_codec_name =
"unknown";
887 case AV_CODEC_ID_AC3:
888 audio_codec_name =
"ac3";
890 case AV_CODEC_ID_EAC3:
891 audio_codec_name =
"eac3";
893 case AV_CODEC_ID_DTS:
894 audio_codec_name =
"dts";
896 case AV_CODEC_ID_TRUEHD:
897 audio_codec_name =
"truehd";
899 case AV_CODEC_ID_MP3:
900 audio_codec_name =
"mp3";
902 case AV_CODEC_ID_MP2:
903 audio_codec_name =
"mp2";
905 case AV_CODEC_ID_AAC:
906 audio_codec_name =
"aac";
908 case AV_CODEC_ID_AAC_LATM:
909 audio_codec_name =
"aac_latm";
912 audio_codec_name =
"unknown";
916 audio_codec_name =
"raw";
919 if (honorCutList && fifo_info)
923 player->TranscodeGetNextFrame(did_ff, is_key,
true);
925 QSize buf_size2 = player->GetVideoBufferSize();
926 video_width = buf_size2.width();
927 video_height = buf_size2.height();
928 video_aspect = player->GetVideoAspect();
929 video_frame_rate = player->GetFrameRate();
933 LOG(VB_GENERAL, LOG_INFO,
934 QString(
"FifoVideoWidth %1").
arg(video_width));
935 LOG(VB_GENERAL, LOG_INFO,
936 QString(
"FifoVideoHeight %1").
arg(video_height));
937 LOG(VB_GENERAL, LOG_INFO,
938 QString(
"FifoVideoAspectRatio %1").
arg(video_aspect));
939 LOG(VB_GENERAL, LOG_INFO,
940 QString(
"FifoVideoFrameRate %1").
arg(video_frame_rate));
941 LOG(VB_GENERAL, LOG_INFO,
942 QString(
"FifoAudioFormat %1").
arg(audio_codec_name));
943 LOG(VB_GENERAL, LOG_INFO,
945 LOG(VB_GENERAL, LOG_INFO,
952 unlink(outputname.toLocal8Bit().constData());
957 QString audfifo = fifodir + QString(
"/audout");
958 QString vidfifo = fifodir + QString(
"/vidout");
962 LOG(VB_GENERAL, LOG_INFO,
"Enforcing sync on fifos");
968 LOG(VB_GENERAL, LOG_ERR,
969 "Error initializing fifo writer. Aborting");
970 unlink(outputname.toLocal8Bit().constData());
974 LOG(VB_GENERAL, LOG_INFO,
975 QString(
"Video %1x%2@%3fps Audio rate: %4")
976 .
arg(video_width).
arg(video_height)
977 .
arg(video_frame_rate)
979 LOG(VB_GENERAL, LOG_INFO,
"Created fifos. Waiting for connection.");
982 #if CONFIG_LIBMP3LAME
983 bool forceKeyFrames = (
m_fifow ==
nullptr) ? framecontrol :
false;
984 bool writekeyframe =
true;
985 long lastKeyFrame = 0;
986 int num_keyframes = 0;
989 frm_dir_map_t::iterator dm_iter;
993 long curFrameNum = 0;
998 std::chrono::milliseconds lasttimecode = 0ms;
1000 std::chrono::milliseconds lastWrittenTime = 0ms;
1002 std::chrono::milliseconds timecodeOffset = 0ms;
1005 float vidFrameTime = 1000.0F / video_frame_rate;
1007 int wait_recover = 0;
1009 bool is_key =
false;
1010 bool first_loop =
true;
1013 struct SwsContext *scontext =
nullptr;
1016 LOG(VB_GENERAL, LOG_INFO,
"Dumping Video and Audio data to fifos");
1018 LOG(VB_GENERAL, LOG_INFO,
"Copying Audio while transcoding Video");
1020 LOG(VB_GENERAL, LOG_INFO,
"Transcoding for HTTP Live Streaming");
1022 LOG(VB_GENERAL, LOG_INFO,
"Transcoding to libavformat container");
1024 LOG(VB_GENERAL, LOG_INFO,
"Transcoding Video and Audio");
1030 QElapsedTimer flagTime;
1034 cutter->Activate(vidFrameTime * rateTimeConv, total_frame_count);
1036 bool stopSignalled =
false;
1042 hls->UpdateStatusMessage(
"Transcoding");
1045 while ((!stopSignalled) &&
1046 (lastDecode = videoBuffer->GetFrame(did_ff, is_key)))
1050 copyaudio = player->GetRawAudioState();
1054 float new_aspect = lastDecode->
m_aspect;
1064 frame.
m_timecode = lasttimecode + vidFrameTimeMs;
1071 scontext = sws_getCachedContext(scontext,
1074 SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr);
1077 sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1078 lastDecode->
m_height, imageOut.data, imageOut.linesize);
1082 std::chrono::milliseconds auddelta = frame.
m_timecode - audbufTime;
1084 std::chrono::milliseconds viddelta = frame.
m_timecode - vidTime;
1085 std::chrono::milliseconds delta = viddelta - auddelta;
1086 std::chrono::milliseconds absdelta = std::chrono::abs(delta);
1087 if (absdelta < 500ms && absdelta >= vidFrameTimeMs)
1089 QString msg = QString(
"Audio is %1ms %2 video at # %3: "
1090 "auddelta=%4, viddelta=%5")
1091 .arg(absdelta.count())
1092 .arg(((delta > 0ms) ?
"ahead of" :
"behind"))
1093 .arg((
int)curFrameNum)
1094 .arg(auddelta.count())
1095 .arg(viddelta.count());
1096 LOG(VB_GENERAL, LOG_INFO, msg);
1097 dropvideo = (delta > 0ms) ? 1 : -1;
1100 else if (delta >= 500ms && delta < 10s)
1102 if (wait_recover == 0)
1107 else if (wait_recover == 1)
1111 while (delta > vidFrameTimeMs)
1113 if (!cutter || !cutter->InhibitDummyFrame())
1117 delta -= vidFrameTimeMs;
1119 QString msg = QString(
"Added %1 blank video frames")
1121 LOG(VB_GENERAL, LOG_INFO, msg);
1122 curFrameNum += count;
1136 int buflen = (int)(arb->audiobuffer_len / rateTimeConv);
1137 LOG(VB_GENERAL, LOG_DEBUG,
1138 QString(
"%1: video time: %2 audio time: %3 "
1139 "buf: %4 exp: %5 delta: %6")
1141 .arg(arb->last_audiotime) .arg(buflen) .arg(audbufTime.count())
1142 .arg(delta.count()));
1148 !cutter->InhibitUseAudioFrames(ab->
m_frames, &totalAudio))
1156 if (cutter && cutter->InhibitDropFrame())
1159 LOG(VB_GENERAL, LOG_INFO,
"Dropping video frame");
1165 if (!cutter || !cutter->InhibitUseVideoFrame())
1170 if (!cutter || !cutter->InhibitDummyFrame())
1178 player->GetCC608Reader()->FlushTxtBuffers();
1183 #if CONFIG_LIBMP3LAME
1186 if (!player->GetRawAudioState())
1189 LOG(VB_GENERAL, LOG_ERR,
"Transcoding aborted, MythPlayer "
1190 "is not in raw audio mode.");
1192 unlink(outputname.toLocal8Bit().constData());
1195 videoBuffer->stop();
1199 hls->UpdateStatusMessage(
"Transcoding Errored");
1205 writekeyframe =
true;
1208 writekeyframe = is_key;
1219 player->UpdateStoredFrameNum(curFrameNum);
1220 m_nvr->UpdateSeekTable(num_keyframes, sync_offset);
1223 lastKeyFrame = curFrameNum;
1232 timecodeOffset += (frame.
m_timecode - lasttimecode - vidFrameTimeMs);
1238 if (!player->WriteStoredData(
m_outBuffer, (did_ff == 0), timecodeOffset))
1240 if (video_aspect != new_aspect)
1242 video_aspect = new_aspect;
1243 m_nvr->SetNewVideoParams(video_aspect);
1246 QSize buf_size3 = player->GetVideoBufferSize();
1248 if (video_width != buf_size3.width() ||
1249 video_height != buf_size3.height())
1251 video_width = buf_size3.width();
1252 video_height = buf_size3.height();
1254 LOG(VB_GENERAL, LOG_INFO,
1255 QString(
"Resizing from %1x%2 to %3x%4")
1256 .
arg(video_width).
arg(video_height)
1257 .
arg(newWidth).
arg(newHeight));
1265 writekeyframe =
true;
1273 int bottomBand = (lastDecode->
m_height == 1088) ? 8 : 0;
1274 scontext = sws_getCachedContext(scontext,
1277 SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr);
1279 sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1281 imageOut.data, imageOut.linesize);
1284 m_nvr->WriteVideo(rescale ? &frame : lastDecode,
true, writekeyframe);
1286 player->GetCC608Reader()->FlushTxtBuffers();
1288 LOG(VB_GENERAL, LOG_ERR,
1289 "Not compiled with libmp3lame support. Should never get here");
1291 #endif // CONFIG_LIBMP3LAME
1298 timecodeOffset += (frame.
m_timecode - lasttimecode -
1302 if (video_aspect != new_aspect)
1304 video_aspect = new_aspect;
1305 #if CONFIG_LIBMP3LAME
1307 m_nvr->SetNewVideoParams(video_aspect);
1312 QSize buf_size4 = player->GetVideoBufferSize();
1314 if (video_width != buf_size4.width() ||
1315 video_height != buf_size4.height())
1317 video_width = buf_size4.width();
1318 video_height = buf_size4.height();
1320 LOG(VB_GENERAL, LOG_INFO,
1321 QString(
"Resizing from %1x%2 to %3x%4")
1322 .
arg(video_width).
arg(video_height)
1323 .
arg(newWidth).
arg(newHeight));
1331 int bottomBand = (lastDecode->
m_height == 1088) ? 8 : 0;
1332 scontext = sws_getCachedContext(scontext,
1335 SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr);
1337 sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
1339 imageOut.data, imageOut.linesize);
1344 while ((ab = arb->
GetData(lastWrittenTime)) !=
nullptr)
1346 auto *buf = (
unsigned char *)ab->
data();
1351 std::chrono::milliseconds tc = ab->
m_time - timecodeOffset;
1352 avfw->WriteAudioFrame(buf, audioFrame, tc);
1356 if ((avfw2->GetTimecodeOffset() == -1ms) &&
1357 (avfw->GetTimecodeOffset() != -1ms))
1359 avfw2->SetTimecodeOffset(
1360 avfw->GetTimecodeOffset());
1363 tc = ab->
m_time - timecodeOffset;
1364 avfw2->WriteAudioFrame(buf, audioFrame, tc);
1370 #if CONFIG_LIBMP3LAME
1373 m_nvr->SetOption(
"audioframesize", ab->
size());
1374 m_nvr->WriteAudio(buf, audioFrame++,
1375 (ab->
m_time - timecodeOffset));
1376 if (m_nvr->IsErrored())
1378 LOG(VB_GENERAL, LOG_ERR,
1379 "Transcode: Encountered irrecoverable error in "
1383 videoBuffer->stop();
1394 #if CONFIG_LIBMP3LAME
1395 player->GetCC608Reader()->
1396 TranscodeWriteText(&TranscodeWriteText, (
void *)(m_nvr));
1398 LOG(VB_GENERAL, LOG_ERR,
1399 "Not compiled with libmp3lame support");
1408 if (halfFramerate && !skippedLastFrame)
1410 skippedLastFrame =
true;
1414 skippedLastFrame =
false;
1417 (avfw->GetFramesWritten()) &&
1418 (hlsSegmentFrames > hlsSegmentSize) &&
1419 (avfw->NextFrameIsKeyFrame()))
1422 avfw->ReOpen(hls->GetCurrentFilename());
1425 avfw2->ReOpen(hls->GetCurrentFilename(
true));
1427 hlsSegmentFrames = 0;
1430 if (avfw->WriteVideoFrame(rescale ? &frame : lastDecode) > 0)
1432 lastWrittenTime = frame.
m_timecode + timecodeOffset;
1439 #if CONFIG_LIBMP3LAME
1443 m_nvr->WriteVideo(rescale ? &frame : lastDecode,
true,
true);
1445 m_nvr->WriteVideo(rescale ? &frame : lastDecode);
1446 lastWrittenTime = frame.
m_timecode + timecodeOffset;
1454 LOG(VB_GENERAL, LOG_INFO,
1455 QString(
"Processed: %1 of %2 frames(%3 seconds)").
1456 arg(curFrameNum).
arg((
long)total_frame_count).
1457 arg((
long)(curFrameNum / video_frame_rate)));
1460 if (hls && hls->CheckStop())
1463 stopSignalled =
true;
1473 LOG(VB_GENERAL, LOG_NOTICE,
1474 "Transcoding aborted, cutlist updated");
1476 unlink(outputname.toLocal8Bit().constData());
1479 videoBuffer->stop();
1487 LOG(VB_GENERAL, LOG_NOTICE,
1488 "Transcoding STOPped by JobQueue");
1490 unlink(outputname.toLocal8Bit().constData());
1493 videoBuffer->stop();
1497 hls->UpdateStatusMessage(
"Transcoding Stopped");
1502 float flagFPS = 0.0;
1503 float elapsed = flagTime.elapsed() / 1000.0;
1504 if (elapsed != 0.0F)
1505 flagFPS = curFrameNum / elapsed;
1507 total_frame_count = player->GetCurrentFrameCount();
1508 int percentage = curFrameNum * 100 / total_frame_count;
1511 hls->UpdatePercentComplete(percentage);
1516 QObject::tr(
"%1% Completed @ %2 fps.")
1517 .
arg(percentage).
arg(flagFPS));
1521 LOG(VB_GENERAL, LOG_INFO,
1522 QString(
"mythtranscode: %1% Completed @ %2 fps.")
1523 .
arg(percentage).
arg(flagFPS));
1533 player->DiscardVideoFrame(lastDecode);
1536 sws_freeContext(scontext);
1554 #if CONFIG_LIBMP3LAME
1557 m_nvr->WriteSeekTable();
1559 m_nvr->WriteKeyFrameAdjustTable(*
m_kfaTable);
1561 #endif // CONFIG_LIBMP3LAME
1571 hls->UpdateStatusMessage(
"Transcoding Completed");
1572 hls->UpdatePercentComplete(100);
1577 hls->UpdateStatusMessage(
"Transcoding Stopped");
1582 videoBuffer->stop();