34 #define ENABLE_VAAPI 0
37 #define MAX_SUPPORTED_WIDTH 1950
38 #define MAX_SUPPORTED_HEIGHT 1100
41 #include "libavutil/hwcontext_vaapi.h"
43 typedef struct VAAPIDecodeContext {
45 VAEntrypoint va_entrypoint;
47 VAContextID va_context;
49 #if FF_API_STRUCT_VAAPI_CONTEXT
52 struct vaapi_context *old_context;
53 AVBufferRef *device_ref;
57 AVHWDeviceContext *device;
58 AVVAAPIDeviceContext *hwctx;
60 AVHWFramesContext *frames;
61 AVVAAPIFramesContext *hwfc;
63 enum AVPixelFormat surface_format;
66 #endif // ENABLE_VAAPI
67 #endif // USE_HW_ACCEL
80 static AVPixelFormat NormalizeDeprecatedPixFmt(AVPixelFormat pix_fmt,
bool& is_full_range) {
82 case AV_PIX_FMT_YUVJ420P:
84 return AV_PIX_FMT_YUV420P;
85 case AV_PIX_FMT_YUVJ422P:
87 return AV_PIX_FMT_YUV422P;
88 case AV_PIX_FMT_YUVJ444P:
90 return AV_PIX_FMT_YUV444P;
91 case AV_PIX_FMT_YUVJ440P:
93 return AV_PIX_FMT_YUV440P;
94 #ifdef AV_PIX_FMT_YUVJ411P
95 case AV_PIX_FMT_YUVJ411P:
97 return AV_PIX_FMT_YUV411P;
108 :
path(
path), pFormatCtx(NULL), videoStream(-1), audioStream(-1), pCodecCtx(NULL), aCodecCtx(NULL),
109 pStream(NULL), aStream(NULL), packet(NULL), pFrame(NULL), is_open(false), is_duration_known(false),
110 check_interlace(false), check_fps(false), duration_strategy(duration_strategy), previous_packet_location{-1, 0},
111 is_seeking(
false), seeking_pts(0), seeking_frame(0), is_video_seek(
true), seek_count(0),
112 seek_audio_frame_found(0), seek_video_frame_found(0), last_seek_max_frame(-1), seek_stagnant_count(0),
113 last_frame(0), largest_frame_processed(0), current_video_frame(0), audio_pts(0), video_pts(0),
114 hold_packet(
false), pts_offset_seconds(0.0), audio_pts_seconds(0.0), video_pts_seconds(0.0),
115 NO_PTS_OFFSET(-99999), source_width(0), source_height(0), source_rotation(0.0), enable_seek(
true) {
122 pts_offset_seconds = NO_PTS_OFFSET;
123 video_pts_seconds = NO_PTS_OFFSET;
124 audio_pts_seconds = NO_PTS_OFFSET;
129 working_cache.SetMaxBytesFromInfo(init_working_cache_frames, info.width, info.height, info.sample_rate, info.channels);
130 final_cache.SetMaxBytesFromInfo(init_final_cache_frames, info.width, info.height, info.sample_rate, info.channels);
133 if (inspect_reader) {
155 if (abs(diff) <= amount)
166 static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx,
const enum AVPixelFormat *pix_fmts)
168 const enum AVPixelFormat *p;
173 for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
175 #if defined(__linux__)
177 case AV_PIX_FMT_VAAPI:
184 case AV_PIX_FMT_VDPAU:
194 case AV_PIX_FMT_DXVA2_VLD:
201 case AV_PIX_FMT_D3D11:
209 #if defined(__APPLE__)
211 case AV_PIX_FMT_VIDEOTOOLBOX:
220 case AV_PIX_FMT_CUDA:
240 return AV_PIX_FMT_NONE;
243 int FFmpegReader::IsHardwareDecodeSupported(
int codecid)
247 case AV_CODEC_ID_H264:
248 case AV_CODEC_ID_MPEG2VIDEO:
249 case AV_CODEC_ID_VC1:
250 case AV_CODEC_ID_WMV1:
251 case AV_CODEC_ID_WMV2:
252 case AV_CODEC_ID_WMV3:
261 #endif // USE_HW_ACCEL
267 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
273 hw_decode_failed =
false;
274 hw_decode_error_count = 0;
275 hw_decode_succeeded =
false;
280 if (avformat_open_input(&pFormatCtx,
path.c_str(), NULL, NULL) != 0)
284 if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
291 packet_status.
reset(
true);
294 for (
unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
296 if (
AV_GET_CODEC_TYPE(pFormatCtx->streams[i]) == AVMEDIA_TYPE_VIDEO && videoStream < 0) {
303 if (
AV_GET_CODEC_TYPE(pFormatCtx->streams[i]) == AVMEDIA_TYPE_AUDIO && audioStream < 0) {
310 if (videoStream == -1 && audioStream == -1)
314 if (videoStream != -1) {
319 pStream = pFormatCtx->streams[videoStream];
325 const AVCodec *pCodec = avcodec_find_decoder(codecId);
326 AVDictionary *
opts = NULL;
327 int retry_decode_open = 2;
332 if (
hw_de_on && (retry_decode_open==2)) {
334 hw_de_supported = IsHardwareDecodeSupported(pCodecCtx->codec_id);
337 retry_decode_open = 0;
342 if (pCodec == NULL) {
343 throw InvalidCodec(
"A valid video codec could not be found for this file.",
path);
347 av_dict_set(&
opts,
"strict",
"experimental", 0);
351 int i_decoder_hw = 0;
353 char *adapter_ptr = NULL;
359 pCodecCtx->get_format = get_hw_dec_format;
361 if (adapter_num < 3 && adapter_num >=0) {
362 #if defined(__linux__)
363 snprintf(adapter,
sizeof(adapter),
"/dev/dri/renderD%d", adapter_num+128);
364 adapter_ptr = adapter;
366 switch (i_decoder_hw) {
368 hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
371 hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA;
374 hw_de_av_device_type = AV_HWDEVICE_TYPE_VDPAU;
377 hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
380 hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
384 #elif defined(_WIN32)
387 switch (i_decoder_hw) {
389 hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA;
392 hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2;
395 hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA;
398 hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
401 hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2;
404 #elif defined(__APPLE__)
407 switch (i_decoder_hw) {
409 hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
412 hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
415 hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
425 #if defined(__linux__)
426 if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) {
427 #elif defined(_WIN32)
428 if( adapter_ptr != NULL ) {
429 #elif defined(__APPLE__)
430 if( adapter_ptr != NULL ) {
439 hw_device_ctx = NULL;
441 if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) {
442 const char* hw_name = av_hwdevice_get_type_name(hw_de_av_device_type);
443 std::string hw_msg =
"HW decode active: ";
444 hw_msg += (hw_name ? hw_name :
"unknown");
446 if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) {
482 #endif // USE_HW_ACCEL
489 pCodecCtx->thread_type &= ~FF_THREAD_FRAME;
493 int avcodec_return = avcodec_open2(pCodecCtx, pCodec, &
opts);
494 if (avcodec_return < 0) {
495 std::stringstream avcodec_error_msg;
496 avcodec_error_msg <<
"A video codec was found, but could not be opened. Error: " << av_err2string(avcodec_return);
502 AVHWFramesConstraints *constraints = NULL;
503 void *hwconfig = NULL;
504 hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx);
508 ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config;
509 constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig);
510 #endif // ENABLE_VAAPI
512 if (pCodecCtx->coded_width < constraints->min_width ||
513 pCodecCtx->coded_height < constraints->min_height ||
514 pCodecCtx->coded_width > constraints->max_width ||
515 pCodecCtx->coded_height > constraints->max_height) {
518 retry_decode_open = 1;
521 av_buffer_unref(&hw_device_ctx);
522 hw_device_ctx = NULL;
527 ZmqLogger::Instance()->
AppendDebugMethod(
"\nDecode hardware acceleration is used\n",
"Min width :", constraints->min_width,
"Min Height :", constraints->min_height,
"MaxWidth :", constraints->max_width,
"MaxHeight :", constraints->max_height,
"Frame width :", pCodecCtx->coded_width,
"Frame height :", pCodecCtx->coded_height);
528 retry_decode_open = 0;
530 av_hwframe_constraints_free(&constraints);
543 if (pCodecCtx->coded_width < 0 ||
544 pCodecCtx->coded_height < 0 ||
545 pCodecCtx->coded_width > max_w ||
546 pCodecCtx->coded_height > max_h ) {
547 ZmqLogger::Instance()->
AppendDebugMethod(
"DIMENSIONS ARE TOO LARGE for hardware acceleration\n",
"Max Width :", max_w,
"Max Height :", max_h,
"Frame width :", pCodecCtx->coded_width,
"Frame height :", pCodecCtx->coded_height);
549 retry_decode_open = 1;
552 av_buffer_unref(&hw_device_ctx);
553 hw_device_ctx = NULL;
557 ZmqLogger::Instance()->
AppendDebugMethod(
"\nDecode hardware acceleration is used\n",
"Max Width :", max_w,
"Max Height :", max_h,
"Frame width :", pCodecCtx->coded_width,
"Frame height :", pCodecCtx->coded_height);
558 retry_decode_open = 0;
566 retry_decode_open = 0;
567 #endif // USE_HW_ACCEL
568 }
while (retry_decode_open);
577 if (audioStream != -1) {
582 aStream = pFormatCtx->streams[audioStream];
588 const AVCodec *aCodec = avcodec_find_decoder(codecId);
594 bool audio_opened =
false;
595 if (aCodec != NULL) {
597 AVDictionary *
opts = NULL;
598 av_dict_set(&
opts,
"strict",
"experimental", 0);
601 audio_opened = (avcodec_open2(aCodecCtx, aCodec, &
opts) >= 0);
612 const bool invalid_audio_info =
617 (aCodecCtx->sample_fmt == AV_SAMPLE_FMT_NONE);
618 if (invalid_audio_info) {
620 "FFmpegReader::Open (Disable invalid audio stream)",
625 "sample_fmt",
static_cast<int>(aCodecCtx ? aCodecCtx->sample_fmt : AV_SAMPLE_FMT_NONE));
631 if (avcodec_is_open(aCodecCtx)) {
632 avcodec_flush_buffers(aCodecCtx);
642 "FFmpegReader::Open (Audio codec unavailable; disabling audio)",
643 "audioStream", audioStream);
659 "FFmpegReader::Open (Invalid FPS detected; applying fallback)",
667 "FFmpegReader::Open (Invalid video_timebase detected; applying fallback)",
674 AVDictionaryEntry *tag = NULL;
675 while ((tag = av_dict_get(pFormatCtx->metadata,
"", tag, AV_DICT_IGNORE_SUFFIX))) {
676 QString str_key = tag->key;
677 QString str_value = tag->value;
678 info.
metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
682 for (
unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
683 AVStream* st = pFormatCtx->streams[i];
684 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
685 size_t side_data_size = 0;
686 const uint8_t *displaymatrix = ffmpeg_stream_get_side_data(
687 st, AV_PKT_DATA_DISPLAYMATRIX, &side_data_size);
689 side_data_size >= 9 *
sizeof(int32_t) &&
691 double rotation = -av_display_rotation_get(
692 reinterpret_cast<const int32_t *
>(displaymatrix));
693 if (std::isnan(rotation))
698 const uint8_t *spherical = ffmpeg_stream_get_side_data(
699 st, AV_PKT_DATA_SPHERICAL, &side_data_size);
700 if (spherical && side_data_size >=
sizeof(AVSphericalMapping)) {
703 const AVSphericalMapping *map =
704 reinterpret_cast<const AVSphericalMapping *
>(spherical);
705 const char *proj_name = av_spherical_projection_name(map->projection);
706 info.
metadata[
"spherical_projection"] = proj_name ? proj_name :
"unknown";
708 auto to_deg = [](int32_t v) {
709 return static_cast<double>(v) / 65536.0;
711 info.
metadata[
"spherical_yaw"] = std::to_string(to_deg(map->yaw));
712 info.
metadata[
"spherical_pitch"] = std::to_string(to_deg(map->pitch));
713 info.
metadata[
"spherical_roll"] = std::to_string(to_deg(map->roll));
718 UpdateOrientedVideoInfo();
721 previous_packet_location.
frame = -1;
755 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
761 AVPacket *recent_packet = packet;
766 int max_attempts = 128;
771 "attempts", attempts);
783 RemoveAVPacket(recent_packet);
788 if(avcodec_is_open(pCodecCtx)) {
789 avcodec_flush_buffers(pCodecCtx);
795 av_buffer_unref(&hw_device_ctx);
796 hw_device_ctx = NULL;
799 #endif // USE_HW_ACCEL
800 if (img_convert_ctx) {
801 sws_freeContext(img_convert_ctx);
802 img_convert_ctx =
nullptr;
804 if (pFrameRGB_cached) {
811 if(avcodec_is_open(aCodecCtx)) {
812 avcodec_flush_buffers(aCodecCtx);
824 working_cache.
Clear();
827 avformat_close_input(&pFormatCtx);
828 av_freep(&pFormatCtx);
835 largest_frame_processed = 0;
836 seek_audio_frame_found = 0;
837 seek_video_frame_found = 0;
838 current_video_frame = 0;
839 last_video_frame.reset();
840 last_final_video_frame.reset();
844 bool FFmpegReader::HasAlbumArt() {
848 return pFormatCtx && videoStream >= 0 && pFormatCtx->streams[videoStream]
849 && (pFormatCtx->streams[videoStream]->disposition & AV_DISPOSITION_ATTACHED_PIC);
852 double FFmpegReader::PickDurationSeconds()
const {
853 auto has_value = [](
double value) {
return value > 0.0; };
855 switch (duration_strategy) {
857 if (has_value(video_stream_duration_seconds))
858 return video_stream_duration_seconds;
859 if (has_value(audio_stream_duration_seconds))
860 return audio_stream_duration_seconds;
861 if (has_value(format_duration_seconds))
862 return format_duration_seconds;
865 if (has_value(audio_stream_duration_seconds))
866 return audio_stream_duration_seconds;
867 if (has_value(video_stream_duration_seconds))
868 return video_stream_duration_seconds;
869 if (has_value(format_duration_seconds))
870 return format_duration_seconds;
875 double longest = 0.0;
876 if (has_value(video_stream_duration_seconds))
877 longest = std::max(longest, video_stream_duration_seconds);
878 if (has_value(audio_stream_duration_seconds))
879 longest = std::max(longest, audio_stream_duration_seconds);
880 if (has_value(format_duration_seconds))
881 longest = std::max(longest, format_duration_seconds);
882 if (has_value(longest))
888 if (has_value(format_duration_seconds))
889 return format_duration_seconds;
890 if (has_value(inferred_duration_seconds))
891 return inferred_duration_seconds;
896 void FFmpegReader::ApplyDurationStrategy() {
898 const double chosen_seconds = PickDurationSeconds();
900 if (chosen_seconds <= 0.0 || fps_value <= 0.0) {
903 is_duration_known =
false;
907 const int64_t frames =
static_cast<int64_t
>(std::llround(chosen_seconds * fps_value));
911 is_duration_known =
false;
916 info.
duration =
static_cast<float>(
static_cast<double>(frames) / fps_value);
917 is_duration_known =
true;
920 void FFmpegReader::UpdateAudioInfo() {
930 AVChannelLayout audio_ch_layout = ffmpeg_get_valid_channel_layout(
932 if (audio_ch_layout.nb_channels > 0) {
935 codec_channels = audio_ch_layout.nb_channels;
947 auto record_duration = [](
double &target,
double seconds) {
949 target = std::max(target, seconds);
954 info.
file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
985 if (aStream->duration > 0) {
988 if (pFormatCtx->duration > 0) {
990 record_duration(format_duration_seconds,
static_cast<double>(pFormatCtx->duration) / AV_TIME_BASE);
1022 ApplyDurationStrategy();
1025 AVDictionaryEntry *tag = NULL;
1026 while ((tag = av_dict_get(aStream->metadata,
"", tag, AV_DICT_IGNORE_SUFFIX))) {
1027 QString str_key = tag->key;
1028 QString str_value = tag->value;
1029 info.
metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
1032 av_channel_layout_uninit(&audio_ch_layout);
1036 void FFmpegReader::UpdateVideoInfo() {
1043 UpdateOrientedVideoInfo();
1048 auto record_duration = [](
double &target,
double seconds) {
1050 target = std::max(target, seconds);
1055 info.
file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
1064 AVRational framerate = av_guess_frame_rate(pFormatCtx, pStream, NULL);
1076 if (pStream->sample_aspect_ratio.num != 0) {
1099 if (!check_interlace) {
1100 check_interlace =
true;
1102 switch(field_order) {
1103 case AV_FIELD_PROGRESSIVE:
1116 case AV_FIELD_UNKNOWN:
1118 check_interlace =
false;
1133 if (pFormatCtx->duration >= 0) {
1135 record_duration(format_duration_seconds,
static_cast<double>(pFormatCtx->duration) / AV_TIME_BASE);
1145 if (video_stream_duration_seconds <= 0.0 && format_duration_seconds <= 0.0 &&
1146 pStream->duration == AV_NOPTS_VALUE && pFormatCtx->duration == AV_NOPTS_VALUE) {
1148 record_duration(video_stream_duration_seconds, 60 * 60 * 1);
1152 if (video_stream_duration_seconds <= 0.0 && format_duration_seconds <= 0.0 &&
1153 pFormatCtx && pFormatCtx->iformat && strcmp(pFormatCtx->iformat->name,
"gif") == 0) {
1154 record_duration(video_stream_duration_seconds, 60 * 60 * 1);
1158 ApplyDurationStrategy();
1164 const bool likely_still_codec =
1165 codec_id == AV_CODEC_ID_MJPEG ||
1166 codec_id == AV_CODEC_ID_PNG ||
1167 codec_id == AV_CODEC_ID_BMP ||
1168 codec_id == AV_CODEC_ID_TIFF ||
1169 codec_id == AV_CODEC_ID_WEBP ||
1170 codec_id == AV_CODEC_ID_JPEG2000;
1171 const bool likely_image_demuxer =
1172 pFormatCtx && pFormatCtx->iformat && pFormatCtx->iformat->name &&
1173 strstr(pFormatCtx->iformat->name,
"image2");
1174 const bool has_attached_pic = HasAlbumArt();
1175 const bool single_frame_stream =
1176 (pStream && pStream->nb_frames > 0 && pStream->nb_frames <= 1);
1179 const bool is_still_image_video =
1181 ((single_frame_stream || single_frame_clip) &&
1182 (likely_still_codec || likely_image_demuxer));
1184 if (is_still_image_video) {
1189 if (audioStream < 0) {
1190 record_duration(video_stream_duration_seconds, 60 * 60 * 1);
1193 ApplyDurationStrategy();
1198 AVDictionaryEntry *tag = NULL;
1199 while ((tag = av_dict_get(pStream->metadata,
"", tag, AV_DICT_IGNORE_SUFFIX))) {
1200 QString str_key = tag->key;
1201 QString str_value = tag->value;
1202 info.
metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
1205 UpdateOrientedVideoInfo();
1208 void FFmpegReader::UpdateOrientedVideoInfo() {
1212 if (source_width <= 0 || source_height <= 0) {
1216 if (source_width <= 0 || source_height <= 0)
1219 source_rotation = 0.0;
1222 source_rotation = strtod(rotate_meta->second.c_str(),
nullptr);
1224 const double radians = source_rotation * M_PI / 180.0;
1225 const int oriented_width =
static_cast<int>(std::round(
1226 std::fabs(source_width * std::cos(radians)) +
1227 std::fabs(source_height * std::sin(radians))));
1228 const int oriented_height =
static_cast<int>(std::round(
1229 std::fabs(source_width * std::sin(radians)) +
1230 std::fabs(source_height * std::cos(radians))));
1232 if (oriented_width > 0 && oriented_height > 0) {
1243 void FFmpegReader::ApplyFrameOrientation(std::shared_ptr<openshot::Frame> frame) {
1247 auto image = frame->GetImage();
1248 if (!image || image->isNull())
1251 QImage oriented = image->transformed(QTransform().rotate(source_rotation), Qt::SmoothTransformation);
1252 frame->AddImage(std::make_shared<QImage>(oriented));
1256 return this->is_duration_known;
1260 last_seek_max_frame = -1;
1261 seek_stagnant_count = 0;
1264 throw ReaderClosed(
"The FFmpegReader is closed. Call Open() before calling this method.",
path);
1267 if (requested_frame < 1)
1268 requested_frame = 1;
1273 throw InvalidFile(
"Could not detect the duration of the video or audio stream.",
path);
1288 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
1301 int64_t diff = requested_frame - last_frame;
1302 if (diff >= 1 && diff <= 20) {
1304 frame = ReadStream(requested_frame);
1309 Seek(requested_frame);
1318 frame = ReadStream(requested_frame);
1326 std::shared_ptr<Frame> FFmpegReader::ReadStream(int64_t requested_frame) {
1328 bool check_seek =
false;
1329 int packet_error = -1;
1330 int64_t no_progress_count = 0;
1331 int64_t prev_packets_read = packet_status.
packets_read();
1334 double prev_video_pts_seconds = video_pts_seconds;
1344 CheckWorkingFrames(requested_frame);
1349 if (is_cache_found) {
1353 if (!hold_packet || !packet) {
1355 packet_error = GetNextPacket();
1356 if (packet_error < 0 && !packet) {
1367 check_seek = CheckSeek();
1379 if ((
info.
has_video && packet && packet->stream_index == videoStream) ||
1383 ProcessVideoPacket(requested_frame);
1384 if (ReopenWithoutHardwareDecode(requested_frame)) {
1389 if ((
info.
has_audio && packet && packet->stream_index == audioStream) ||
1393 ProcessAudioPacket(requested_frame);
1398 if ((!
info.
has_video && packet && packet->stream_index == videoStream) ||
1399 (!
info.
has_audio && packet && packet->stream_index == audioStream)) {
1401 if (packet->stream_index == videoStream) {
1403 }
else if (packet->stream_index == audioStream) {
1409 RemoveAVPacket(packet);
1419 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::ReadStream (force EOF)",
"packets_read", packet_status.
packets_read(),
"packets_decoded", packet_status.
packets_decoded(),
"packets_eof", packet_status.
packets_eof,
"video_eof", packet_status.
video_eof,
"audio_eof", packet_status.
audio_eof,
"end_of_file", packet_status.
end_of_file);
1432 const bool has_progress =
1436 (video_pts_seconds != prev_video_pts_seconds);
1439 no_progress_count = 0;
1441 no_progress_count++;
1442 if (no_progress_count >= 2000
1447 "requested_frame", requested_frame,
1448 "no_progress_count", no_progress_count,
1462 prev_video_pts_seconds = video_pts_seconds;
1470 "largest_frame_processed", largest_frame_processed,
1471 "Working Cache Count", working_cache.
Count());
1480 CheckWorkingFrames(requested_frame);
1496 std::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
1497 if (frame->has_image_data) {
1498 f->AddImage(std::make_shared<QImage>(frame->GetImage()->copy()));
1502 if (!frame->has_image_data) {
1507 f->AddAudioSilence(samples_in_frame);
1513 std::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
1514 if (last_final_video_frame && last_final_video_frame->has_image_data
1515 && last_final_video_frame->number <= requested_frame) {
1516 f->AddImage(std::make_shared<QImage>(last_final_video_frame->GetImage()->copy()));
1517 }
else if (last_video_frame && last_video_frame->has_image_data
1518 && last_video_frame->number <= requested_frame) {
1519 f->AddImage(std::make_shared<QImage>(last_video_frame->GetImage()->copy()));
1523 f->AddAudioSilence(samples_in_frame);
1531 int FFmpegReader::GetNextPacket() {
1532 int found_packet = 0;
1533 AVPacket *next_packet;
1534 next_packet =
new AVPacket();
1535 found_packet = av_read_frame(pFormatCtx, next_packet);
1539 RemoveAVPacket(packet);
1542 if (found_packet >= 0) {
1544 packet = next_packet;
1547 if (packet->stream_index == videoStream) {
1549 }
else if (packet->stream_index == audioStream) {
1558 return found_packet;
1562 bool FFmpegReader::GetAVFrame() {
1563 int frameFinished = 0;
1564 auto note_hw_decode_failure = [&](
int err,
const char* stage) {
1566 if (!
hw_de_on || !hw_de_supported || force_sw_decode) {
1569 if (err == AVERROR_INVALIDDATA && packet_status.
video_decoded == 0) {
1570 hw_decode_error_count++;
1572 std::string(
"FFmpegReader::GetAVFrame (hardware decode failure candidate during ") + stage +
")",
1573 "error_count", hw_decode_error_count,
1575 if (hw_decode_error_count >= 3) {
1576 hw_decode_failed =
true;
1589 int send_packet_err = 0;
1590 int64_t send_packet_pts = 0;
1591 if ((packet && packet->stream_index == videoStream) || !packet) {
1592 send_packet_err = avcodec_send_packet(pCodecCtx, packet);
1594 if (packet && send_packet_err >= 0) {
1595 send_packet_pts = GetPacketPTS();
1596 hold_packet =
false;
1605 #endif // USE_HW_ACCEL
1606 if (send_packet_err < 0 && send_packet_err != AVERROR_EOF) {
1607 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::GetAVFrame (send packet: Not sent [" + av_err2string(send_packet_err) +
"])",
"send_packet_err", send_packet_err,
"send_packet_pts", send_packet_pts);
1608 note_hw_decode_failure(send_packet_err,
"send_packet");
1609 if (send_packet_err == AVERROR(EAGAIN)) {
1611 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::GetAVFrame (send packet: AVERROR(EAGAIN): user must read output with avcodec_receive_frame()",
"send_packet_pts", send_packet_pts);
1613 if (send_packet_err == AVERROR(EINVAL)) {
1614 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::GetAVFrame (send packet: AVERROR(EINVAL): codec not opened, it is an encoder, or requires flush",
"send_packet_pts", send_packet_pts);
1616 if (send_packet_err == AVERROR(ENOMEM)) {
1617 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::GetAVFrame (send packet: AVERROR(ENOMEM): failed to add packet to internal queue, or legitimate decoding errors",
"send_packet_pts", send_packet_pts);
1624 int receive_frame_err = 0;
1625 AVFrame *decoded_frame = next_frame;
1626 AVFrame *next_frame2;
1632 #endif // USE_HW_ACCEL
1634 next_frame2 = next_frame;
1637 while (receive_frame_err >= 0) {
1638 receive_frame_err = avcodec_receive_frame(pCodecCtx, next_frame2);
1640 if (receive_frame_err != 0) {
1641 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::GetAVFrame (receive frame: frame not ready yet from decoder [\" + av_err2string(receive_frame_err) + \"])",
"receive_frame_err", receive_frame_err,
"send_packet_pts", send_packet_pts);
1642 note_hw_decode_failure(receive_frame_err,
"receive_frame");
1644 if (receive_frame_err == AVERROR_EOF) {
1646 "FFmpegReader::GetAVFrame (receive frame: AVERROR_EOF: EOF detected from decoder, flushing buffers)",
"send_packet_pts", send_packet_pts);
1647 avcodec_flush_buffers(pCodecCtx);
1650 if (receive_frame_err == AVERROR(EINVAL)) {
1652 "FFmpegReader::GetAVFrame (receive frame: AVERROR(EINVAL): invalid frame received, flushing buffers)",
"send_packet_pts", send_packet_pts);
1653 avcodec_flush_buffers(pCodecCtx);
1655 if (receive_frame_err == AVERROR(EAGAIN)) {
1657 "FFmpegReader::GetAVFrame (receive frame: AVERROR(EAGAIN): output is not available in this state - user must try to send new input)",
"send_packet_pts", send_packet_pts);
1659 if (receive_frame_err == AVERROR_INPUT_CHANGED) {
1661 "FFmpegReader::GetAVFrame (receive frame: AVERROR_INPUT_CHANGED: current decoded frame has changed parameters with respect to first decoded frame)",
"send_packet_pts", send_packet_pts);
1672 if (next_frame2->format == hw_de_av_pix_fmt) {
1673 if ((err = av_hwframe_transfer_data(next_frame, next_frame2, 0)) < 0) {
1675 "FFmpegReader::GetAVFrame (Failed to transfer data to output frame)",
1678 note_hw_decode_failure(AVERROR_INVALIDDATA,
"hwframe_transfer");
1681 if ((err = av_frame_copy_props(next_frame, next_frame2)) < 0) {
1683 "FFmpegReader::GetAVFrame (Failed to copy props to output frame)",
1686 note_hw_decode_failure(AVERROR_INVALIDDATA,
"hwframe_copy_props");
1689 if (next_frame->format == AV_PIX_FMT_NONE) {
1690 next_frame->format = pCodecCtx->sw_pix_fmt;
1692 if (next_frame->width <= 0) {
1693 next_frame->width = next_frame2->width;
1695 if (next_frame->height <= 0) {
1696 next_frame->height = next_frame2->height;
1698 decoded_frame = next_frame;
1701 decoded_frame = next_frame2;
1705 #endif // USE_HW_ACCEL
1707 decoded_frame = next_frame2;
1710 if (!decoded_frame->data[0]) {
1712 "FFmpegReader::GetAVFrame (Decoded frame missing image data)",
1713 "format", decoded_frame->format,
1714 "width", decoded_frame->width,
1715 "height", decoded_frame->height);
1716 note_hw_decode_failure(AVERROR_INVALIDDATA,
"decoded_frame_empty");
1723 hw_decode_error_count = 0;
1725 if (
hw_de_on && hw_de_supported && !force_sw_decode) {
1726 hw_decode_succeeded =
true;
1732 AVPixelFormat decoded_pix_fmt = (AVPixelFormat)(decoded_frame->format);
1733 if (decoded_pix_fmt == AV_PIX_FMT_NONE)
1734 decoded_pix_fmt = (AVPixelFormat)(pStream->codecpar->format);
1735 const int decoded_width = decoded_frame->width > 0 ? decoded_frame->width :
info.
width;
1736 const int decoded_height = decoded_frame->height > 0 ? decoded_frame->height :
info.
height;
1737 if (
AV_ALLOCATE_IMAGE(pFrame, decoded_pix_fmt, decoded_width, decoded_height) <= 0) {
1740 av_image_copy(pFrame->data, pFrame->linesize, (
const uint8_t**)decoded_frame->data, decoded_frame->linesize,
1741 decoded_pix_fmt, decoded_width, decoded_height);
1742 pFrame->format = decoded_pix_fmt;
1743 pFrame->width = decoded_width;
1744 pFrame->height = decoded_height;
1745 pFrame->color_range = decoded_frame->color_range;
1746 pFrame->colorspace = decoded_frame->colorspace;
1747 pFrame->color_primaries = decoded_frame->color_primaries;
1748 pFrame->color_trc = decoded_frame->color_trc;
1749 pFrame->chroma_location = decoded_frame->chroma_location;
1755 if (decoded_frame->pts != AV_NOPTS_VALUE) {
1758 video_pts = decoded_frame->pts;
1759 }
else if (decoded_frame->pkt_dts != AV_NOPTS_VALUE) {
1761 video_pts = decoded_frame->pkt_dts;
1765 "FFmpegReader::GetAVFrame (Successful frame received)",
"video_pts", video_pts,
"send_packet_pts", send_packet_pts);
1771 if (
hw_de_on && hw_de_supported && next_frame2 != next_frame) {
1774 #endif // USE_HW_ACCEL
1776 avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);
1782 if (frameFinished) {
1786 av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt,
info.
width,
1789 #endif // IS_FFMPEG_3_2
1795 return frameFinished;
1798 bool FFmpegReader::ReopenWithoutHardwareDecode(int64_t requested_frame) {
1800 if (!hw_decode_failed || force_sw_decode) {
1805 "FFmpegReader::ReopenWithoutHardwareDecode (falling back to software decode)",
1806 "requested_frame", requested_frame,
1807 "video_packets_read", packet_status.
video_read,
1809 "hw_decode_error_count", hw_decode_error_count);
1811 force_sw_decode =
true;
1812 hw_decode_failed =
false;
1813 hw_decode_error_count = 0;
1817 Seek(requested_frame);
1820 (void) requested_frame;
1827 return hw_decode_succeeded;
1834 bool FFmpegReader::CheckSeek() {
1837 const int64_t kSeekRetryMax = 5;
1838 const int kSeekStagnantMax = 2;
1842 if ((is_video_seek && !seek_video_frame_found) || (!is_video_seek && !seek_audio_frame_found))
1850 int64_t max_seeked_frame = std::max(seek_audio_frame_found, seek_video_frame_found);
1852 if (max_seeked_frame == last_seek_max_frame) {
1853 seek_stagnant_count++;
1855 last_seek_max_frame = max_seeked_frame;
1856 seek_stagnant_count = 0;
1860 if (max_seeked_frame >= seeking_frame) {
1863 "is_video_seek", is_video_seek,
1864 "max_seeked_frame", max_seeked_frame,
1865 "seeking_frame", seeking_frame,
1866 "seeking_pts", seeking_pts,
1867 "seek_video_frame_found", seek_video_frame_found,
1868 "seek_audio_frame_found", seek_audio_frame_found);
1871 if (seek_count < kSeekRetryMax) {
1872 Seek(seeking_frame - (10 * seek_count * seek_count));
1873 }
else if (seek_stagnant_count >= kSeekStagnantMax) {
1875 Seek(seeking_frame - (10 * kSeekRetryMax * kSeekRetryMax));
1878 Seek(seeking_frame - (10 * seek_count * seek_count));
1883 "is_video_seek", is_video_seek,
1884 "packet->pts", GetPacketPTS(),
1885 "seeking_pts", seeking_pts,
1886 "seeking_frame", seeking_frame,
1887 "seek_video_frame_found", seek_video_frame_found,
1888 "seek_audio_frame_found", seek_audio_frame_found);
1902 void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) {
1905 int frame_finished = GetAVFrame();
1908 if (!frame_finished) {
1911 RemoveAVFrame(pFrame);
1917 int64_t current_frame = ConvertVideoPTStoFrame(video_pts);
1920 if (!seek_video_frame_found && is_seeking)
1921 seek_video_frame_found = current_frame;
1927 working_cache.
Add(CreateFrame(requested_frame));
1933 AVPixelFormat decoded_pix_fmt = (pFrame && pFrame->format != AV_PIX_FMT_NONE)
1934 ?
static_cast<AVPixelFormat
>(pFrame->format)
1936 bool src_full_range = (pFrame && pFrame->color_range == AVCOL_RANGE_JPEG);
1937 AVPixelFormat src_pix_fmt = NormalizeDeprecatedPixFmt(decoded_pix_fmt, src_full_range);
1938 int src_width = (pFrame && pFrame->width > 0) ? pFrame->width :
info.
width;
1939 int src_height = (pFrame && pFrame->height > 0) ? pFrame->height :
info.
height;
1940 int height = src_height;
1941 int width = src_width;
1943 AVFrame *pFrameRGB = pFrameRGB_cached;
1946 if (pFrameRGB ==
nullptr)
1948 pFrameRGB_cached = pFrameRGB;
1951 uint8_t *buffer =
nullptr;
1972 max_width = std::max(
float(max_width), max_width * max_scale_x);
1973 max_height = std::max(
float(max_height), max_height * max_scale_y);
1979 QSize width_size(max_width * max_scale_x,
1982 max_height * max_scale_y);
1984 if (width_size.width() >= max_width && width_size.height() >= max_height) {
1985 max_width = std::max(max_width, width_size.width());
1986 max_height = std::max(max_height, width_size.height());
1988 max_width = std::max(max_width, height_size.width());
1989 max_height = std::max(max_height, height_size.height());
1996 float preview_ratio = 1.0;
2003 max_width =
info.
width * max_scale_x * preview_ratio;
2004 max_height =
info.
height * max_scale_y * preview_ratio;
2012 QSize bounded_size(max_width, max_height);
2014 if (bounded_size.width() > max_decode_size.width() ||
2015 bounded_size.height() > max_decode_size.height()) {
2016 bounded_size.scale(max_decode_size, Qt::KeepAspectRatio);
2017 max_width = bounded_size.width();
2018 max_height = bounded_size.height();
2025 const int quarter_turn = ((
static_cast<int>(std::round(source_rotation / 90.0)) * 90) % 360 + 360) % 360;
2027 std::swap(max_width, max_height);
2031 int original_height = src_height;
2032 if (max_width != 0 && max_height != 0 && max_width < width && max_height < height) {
2034 float ratio = float(width) / float(height);
2035 int possible_width = round(max_height * ratio);
2036 int possible_height = round(max_width / ratio);
2038 if (possible_width <= max_width) {
2040 width = possible_width;
2041 height = max_height;
2045 height = possible_height;
2050 const int bytes_per_pixel = 4;
2051 int raw_buffer_size = (width * height * bytes_per_pixel) + 128;
2054 constexpr
size_t ALIGNMENT = 32;
2055 int buffer_size = ((raw_buffer_size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
2056 buffer = (
unsigned char*) aligned_malloc(buffer_size, ALIGNMENT);
2061 int scale_mode = SWS_FAST_BILINEAR;
2063 scale_mode = SWS_BICUBIC;
2065 img_convert_ctx = sws_getCachedContext(img_convert_ctx, src_width, src_height, src_pix_fmt, width, height,
PIX_FMT_RGBA, scale_mode, NULL, NULL, NULL);
2066 if (!img_convert_ctx)
2068 const int *src_coeff = sws_getCoefficients(SWS_CS_DEFAULT);
2069 const int *dst_coeff = sws_getCoefficients(SWS_CS_DEFAULT);
2070 const int dst_full_range = 1;
2071 sws_setColorspaceDetails(img_convert_ctx, src_coeff, src_full_range ? 1 : 0,
2072 dst_coeff, dst_full_range, 0, 1 << 16, 1 << 16);
2074 if (!pFrame || !pFrame->data[0] || pFrame->linesize[0] <= 0) {
2076 if (
hw_de_on && hw_de_supported && !force_sw_decode) {
2077 hw_decode_failed =
true;
2079 "FFmpegReader::ProcessVideoPacket (Invalid source frame; forcing software fallback)",
2080 "requested_frame", requested_frame,
2081 "current_frame", current_frame,
2082 "src_pix_fmt", src_pix_fmt,
2083 "src_width", src_width,
2084 "src_height", src_height);
2088 RemoveAVFrame(pFrame);
2095 const int scaled_lines = sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,
2096 original_height, pFrameRGB->data, pFrameRGB->linesize);
2097 if (scaled_lines <= 0) {
2099 if (
hw_de_on && hw_de_supported && !force_sw_decode) {
2100 hw_decode_failed =
true;
2102 "FFmpegReader::ProcessVideoPacket (sws_scale failed; forcing software fallback)",
2103 "requested_frame", requested_frame,
2104 "current_frame", current_frame,
2105 "scaled_lines", scaled_lines,
2106 "src_pix_fmt", src_pix_fmt,
2107 "src_width", src_width,
2108 "src_height", src_height);
2113 RemoveAVFrame(pFrame);
2119 std::shared_ptr<Frame> f = CreateFrame(current_frame);
2122 if (!ffmpeg_has_alpha(src_pix_fmt)) {
2124 f->AddImage(width, height, bytes_per_pixel, QImage::Format_RGBA8888_Premultiplied, buffer);
2127 f->AddImage(width, height, bytes_per_pixel, QImage::Format_RGBA8888, buffer);
2129 ApplyFrameOrientation(f);
2132 working_cache.
Add(f);
2135 last_video_frame = f;
2141 RemoveAVFrame(pFrame);
2147 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::ProcessVideoPacket (After)",
"requested_frame", requested_frame,
"current_frame", current_frame,
"f->number", f->number,
"video_pts_seconds", video_pts_seconds);
2151 void FFmpegReader::ProcessAudioPacket(int64_t requested_frame) {
2154 if (packet && packet->pts != AV_NOPTS_VALUE) {
2156 location = GetAudioPTSLocation(packet->pts);
2159 if (!seek_audio_frame_found && is_seeking)
2160 seek_audio_frame_found = location.
frame;
2167 working_cache.
Add(CreateFrame(requested_frame));
2171 "requested_frame", requested_frame,
2172 "target_frame", location.
frame,
2176 int frame_finished = 0;
2180 int packet_samples = 0;
2184 int send_packet_err = avcodec_send_packet(aCodecCtx, packet);
2185 if (send_packet_err < 0 && send_packet_err != AVERROR_EOF) {
2189 int receive_frame_err = avcodec_receive_frame(aCodecCtx, audio_frame);
2190 if (receive_frame_err >= 0) {
2193 if (receive_frame_err == AVERROR_EOF) {
2197 if (receive_frame_err == AVERROR(EINVAL) || receive_frame_err == AVERROR_EOF) {
2199 avcodec_flush_buffers(aCodecCtx);
2201 if (receive_frame_err != 0) {
2206 int used = avcodec_decode_audio4(aCodecCtx, audio_frame, &frame_finished, packet);
2209 if (frame_finished) {
2215 audio_pts = audio_frame->pts;
2218 location = GetAudioPTSLocation(audio_pts);
2221 int plane_size = -1;
2227 data_size = av_samples_get_buffer_size(&plane_size, nb_channels,
2231 packet_samples = audio_frame->nb_samples * nb_channels;
2240 int pts_remaining_samples = packet_samples /
info.
channels;
2243 if (pts_remaining_samples == 0) {
2245 "packet_samples", packet_samples,
2247 "pts_remaining_samples", pts_remaining_samples);
2251 while (pts_remaining_samples) {
2256 int samples = samples_per_frame - previous_packet_location.
sample_start;
2257 if (samples > pts_remaining_samples)
2258 samples = pts_remaining_samples;
2261 pts_remaining_samples -= samples;
2263 if (pts_remaining_samples > 0) {
2265 previous_packet_location.
frame++;
2274 "packet_samples", packet_samples,
2282 audio_converted->nb_samples = audio_frame->nb_samples;
2283 av_samples_alloc(audio_converted->data, audio_converted->linesize,
info.
channels, audio_frame->nb_samples, AV_SAMPLE_FMT_FLTP, 0);
2290 AVChannelLayout input_layout = ffmpeg_get_valid_channel_layout(
2292 AVChannelLayout output_layout = ffmpeg_get_valid_channel_layout(
2294 int in_layout_err = av_opt_set_chlayout(avr,
"in_chlayout", &input_layout, 0);
2295 int out_layout_err = av_opt_set_chlayout(avr,
"out_chlayout", &output_layout, 0);
2303 av_opt_set_int(avr,
"out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
2308 av_channel_layout_uninit(&input_layout);
2309 av_channel_layout_uninit(&output_layout);
2310 if (in_layout_err < 0 || out_layout_err < 0 || swr_init_err < 0) {
2312 throw InvalidChannels(
"Could not initialize FFmpeg audio channel layout or resampler.",
path);
2315 if (swr_init_err < 0) {
2325 audio_converted->data,
2326 audio_converted->linesize[0],
2327 audio_converted->nb_samples,
2329 audio_frame->linesize[0],
2330 audio_frame->nb_samples);
2333 int64_t starting_frame_number = -1;
2334 for (
int channel_filter = 0; channel_filter <
info.
channels; channel_filter++) {
2336 starting_frame_number = location.
frame;
2337 int channel_buffer_size = nb_samples;
2338 auto *channel_buffer = (
float *) (audio_converted->data[channel_filter]);
2342 int remaining_samples = channel_buffer_size;
2343 while (remaining_samples > 0) {
2348 int samples = std::fmin(samples_per_frame - start, remaining_samples);
2351 std::shared_ptr<Frame> f = CreateFrame(starting_frame_number);
2354 f->AddAudio(
true, channel_filter, start, channel_buffer, samples, 1.0f);
2358 "frame", starting_frame_number,
2361 "channel", channel_filter,
2362 "samples_per_frame", samples_per_frame);
2365 working_cache.
Add(f);
2368 remaining_samples -= samples;
2371 if (remaining_samples > 0)
2372 channel_buffer += samples;
2375 starting_frame_number++;
2383 av_free(audio_converted->data[0]);
2392 "requested_frame", requested_frame,
2393 "starting_frame", location.
frame,
2394 "end_frame", starting_frame_number - 1,
2395 "audio_pts_seconds", audio_pts_seconds);
2401 void FFmpegReader::Seek(int64_t requested_frame) {
2403 if (requested_frame < 1)
2404 requested_frame = 1;
2407 if (requested_frame > largest_frame_processed && packet_status.
end_of_file) {
2414 "requested_frame", requested_frame,
2415 "seek_count", seek_count,
2416 "last_frame", last_frame);
2419 working_cache.
Clear();
2423 video_pts_seconds = NO_PTS_OFFSET;
2425 audio_pts_seconds = NO_PTS_OFFSET;
2426 hold_packet =
false;
2428 current_video_frame = 0;
2429 largest_frame_processed = 0;
2430 last_final_video_frame.reset();
2435 packet_status.
reset(
false);
2441 int buffer_amount = 12;
2442 if (requested_frame - buffer_amount < 20) {
2456 if (seek_count == 1) {
2459 seeking_pts = ConvertFrameToVideoPTS(1);
2461 seek_audio_frame_found = 0;
2462 seek_video_frame_found = 0;
2466 bool seek_worked =
false;
2467 int64_t seek_target = 0;
2471 seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount);
2476 is_video_seek =
true;
2483 seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount);
2488 is_video_seek =
false;
2497 avcodec_flush_buffers(aCodecCtx);
2501 avcodec_flush_buffers(pCodecCtx);
2504 previous_packet_location.
frame = -1;
2509 if (seek_count == 1) {
2511 seeking_pts = seek_target;
2512 seeking_frame = requested_frame;
2514 seek_audio_frame_found = 0;
2515 seek_video_frame_found = 0;
2543 int64_t FFmpegReader::GetPacketPTS() {
2545 int64_t current_pts = packet->pts;
2546 if (current_pts == AV_NOPTS_VALUE && packet->dts != AV_NOPTS_VALUE)
2547 current_pts = packet->dts;
2553 return AV_NOPTS_VALUE;
2558 void FFmpegReader::UpdatePTSOffset() {
2559 if (pts_offset_seconds != NO_PTS_OFFSET) {
2563 pts_offset_seconds = 0.0;
2564 double video_pts_offset_seconds = 0.0;
2565 double audio_pts_offset_seconds = 0.0;
2567 bool has_video_pts =
false;
2570 has_video_pts =
true;
2572 bool has_audio_pts =
false;
2575 has_audio_pts =
true;
2579 while (!has_video_pts || !has_audio_pts) {
2581 if (GetNextPacket() < 0)
2586 int64_t pts = GetPacketPTS();
2589 if (!has_video_pts && packet->stream_index == videoStream) {
2595 if (std::abs(video_pts_offset_seconds) <= 10.0) {
2596 has_video_pts =
true;
2599 else if (!has_audio_pts && packet->stream_index == audioStream) {
2605 if (std::abs(audio_pts_offset_seconds) <= 10.0) {
2606 has_audio_pts =
true;
2616 pts_offset_seconds = video_pts_offset_seconds;
2618 pts_offset_seconds = audio_pts_offset_seconds;
2619 }
else if (has_video_pts && has_audio_pts) {
2621 pts_offset_seconds = video_pts_offset_seconds;
2626 int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) {
2628 int64_t previous_video_frame = current_video_frame;
2630 const double video_timebase_value =
2636 double video_seconds = (double(pts) * video_timebase_value) + pts_offset_seconds;
2639 int64_t frame = round(video_seconds * fps_value) + 1;
2642 if (current_video_frame == 0)
2643 current_video_frame = frame;
2647 if (frame == previous_video_frame) {
2652 current_video_frame++;
2661 int64_t FFmpegReader::ConvertFrameToVideoPTS(int64_t frame_number) {
2663 const double video_timebase_value =
2669 double seconds = (double(frame_number - 1) / fps_value) + pts_offset_seconds;
2672 int64_t video_pts = round(seconds / video_timebase_value);
2679 int64_t FFmpegReader::ConvertFrameToAudioPTS(int64_t frame_number) {
2681 const double audio_timebase_value =
2687 double seconds = (double(frame_number - 1) / fps_value) + pts_offset_seconds;
2690 int64_t audio_pts = round(seconds / audio_timebase_value);
2697 AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) {
2698 const double audio_timebase_value =
2705 double audio_seconds = (double(pts) * audio_timebase_value) + pts_offset_seconds;
2708 double frame = (audio_seconds * fps_value) + 1;
2711 int64_t whole_frame = int64_t(frame);
2714 double sample_start_percentage = frame - double(whole_frame);
2720 int sample_start = round(
double(samples_per_frame) * sample_start_percentage);
2723 if (whole_frame < 1)
2725 if (sample_start < 0)
2732 if (previous_packet_location.
frame != -1) {
2733 if (location.
is_near(previous_packet_location, samples_per_frame, samples_per_frame)) {
2734 int64_t orig_frame = location.
frame;
2739 location.
frame = previous_packet_location.
frame;
2742 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::GetAudioPTSLocation (Audio Gap Detected)",
"Source Frame", orig_frame,
"Source Audio Sample", orig_start,
"Target Frame", location.
frame,
"Target Audio Sample", location.
sample_start,
"pts", pts);
2751 previous_packet_location = location;
2758 std::shared_ptr<Frame> FFmpegReader::CreateFrame(int64_t requested_frame) {
2760 std::shared_ptr<Frame> output = working_cache.
GetFrame(requested_frame);
2764 output = working_cache.
GetFrame(requested_frame);
2765 if(output)
return output;
2773 working_cache.
Add(output);
2776 if (requested_frame > largest_frame_processed)
2777 largest_frame_processed = requested_frame;
2784 bool FFmpegReader::IsPartialFrame(int64_t requested_frame) {
2787 bool seek_trash =
false;
2788 int64_t max_seeked_frame = seek_audio_frame_found;
2789 if (seek_video_frame_found > max_seeked_frame) {
2790 max_seeked_frame = seek_video_frame_found;
2792 if ((
info.
has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) ||
2793 (
info.
has_video && seek_video_frame_found && max_seeked_frame >= requested_frame)) {
2801 void FFmpegReader::CheckWorkingFrames(int64_t requested_frame) {
2804 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
2807 std::vector<std::shared_ptr<openshot::Frame>> working_frames = working_cache.
GetFrames();
2808 std::vector<std::shared_ptr<openshot::Frame>>::iterator working_itr;
2811 for(working_itr = working_frames.begin(); working_itr != working_frames.end(); ++working_itr)
2814 std::shared_ptr<Frame> f = *working_itr;
2817 if (!f || f->number > requested_frame) {
2823 double frame_pts_seconds = (double(f->number - 1) /
info.
fps.
ToDouble()) + pts_offset_seconds;
2824 double recent_pts_seconds = std::max(video_pts_seconds, audio_pts_seconds);
2827 bool is_video_ready =
false;
2828 bool is_audio_ready =
false;
2829 double recent_pts_diff = recent_pts_seconds - frame_pts_seconds;
2830 if ((frame_pts_seconds <= video_pts_seconds)
2831 || (recent_pts_diff > 1.5)
2835 is_video_ready =
true;
2837 "frame_number", f->number,
2838 "frame_pts_seconds", frame_pts_seconds,
2839 "video_pts_seconds", video_pts_seconds,
2840 "recent_pts_diff", recent_pts_diff);
2846 if (previous_frame_instance && previous_frame_instance->has_image_data) {
2847 f->AddImage(std::make_shared<QImage>(previous_frame_instance->GetImage()->copy()));
2851 if (!f->has_image_data
2852 && last_final_video_frame
2853 && last_final_video_frame->has_image_data
2854 && last_final_video_frame->number <= f->number) {
2855 f->AddImage(std::make_shared<QImage>(last_final_video_frame->GetImage()->copy()));
2859 if (!f->has_image_data
2861 && last_video_frame->has_image_data
2862 && last_video_frame->number <= f->number) {
2863 f->AddImage(std::make_shared<QImage>(last_video_frame->GetImage()->copy()));
2867 if (!f->has_image_data) {
2869 "FFmpegReader::CheckWorkingFrames (no previous image found; using black frame)",
2870 "frame_number", f->number);
2871 f->AddColor(
"#000000");
2876 double audio_pts_diff = audio_pts_seconds - frame_pts_seconds;
2877 if ((frame_pts_seconds < audio_pts_seconds && audio_pts_diff > 1.0)
2878 || (recent_pts_diff > 1.5)
2883 is_audio_ready =
true;
2885 "frame_number", f->number,
2886 "frame_pts_seconds", frame_pts_seconds,
2887 "audio_pts_seconds", audio_pts_seconds,
2888 "audio_pts_diff", audio_pts_diff,
2889 "recent_pts_diff", recent_pts_diff);
2891 bool is_seek_trash = IsPartialFrame(f->number);
2899 "frame_number", f->number,
2900 "is_video_ready", is_video_ready,
2901 "is_audio_ready", is_audio_ready,
2908 && !packet_status.
end_of_file && !is_seek_trash) {
2913 if (previous_frame_instance && previous_frame_instance->has_image_data) {
2914 f->AddImage(std::make_shared<QImage>(previous_frame_instance->GetImage()->copy()));
2916 if (!f->has_image_data
2917 && last_final_video_frame
2918 && last_final_video_frame->has_image_data
2919 && last_final_video_frame->number <= f->number) {
2920 f->AddImage(std::make_shared<QImage>(last_final_video_frame->GetImage()->copy()));
2922 if (!f->has_image_data
2924 && last_video_frame->has_image_data
2925 && last_video_frame->number <= f->number) {
2926 f->AddImage(std::make_shared<QImage>(last_video_frame->GetImage()->copy()));
2933 if (!f->has_image_data && is_video_ready && is_audio_ready) {
2935 if (previous_frame_instance && previous_frame_instance->has_image_data) {
2936 f->AddImage(std::make_shared<QImage>(previous_frame_instance->GetImage()->copy()));
2938 if (!f->has_image_data
2939 && last_final_video_frame
2940 && last_final_video_frame->has_image_data
2941 && last_final_video_frame->number <= f->number) {
2942 f->AddImage(std::make_shared<QImage>(last_final_video_frame->GetImage()->copy()));
2944 if (!f->has_image_data
2946 && last_video_frame->has_image_data
2947 && last_video_frame->number <= f->number) {
2948 f->AddImage(std::make_shared<QImage>(last_video_frame->GetImage()->copy()));
2954 if (!f->has_image_data) {
2958 if ((!packet_status.
end_of_file && is_video_ready && is_audio_ready) || packet_status.
end_of_file || is_seek_trash) {
2961 "requested_frame", requested_frame,
2962 "f->number", f->number,
2963 "is_seek_trash", is_seek_trash,
2964 "Working Cache Count", working_cache.
Count(),
2968 if (!is_seek_trash) {
2971 if (f->has_image_data) {
2972 last_final_video_frame = f;
2976 working_cache.
Remove(f->number);
2979 last_frame = f->number;
2982 working_cache.
Remove(f->number);
2989 working_frames.clear();
2990 working_frames.shrink_to_fit();
2994 void FFmpegReader::CheckFPS() {
3002 int frames_per_second[3] = {0,0,0};
3003 int max_fps_index =
sizeof(frames_per_second) /
sizeof(frames_per_second[0]);
3006 int all_frames_detected = 0;
3007 int starting_frames_detected = 0;
3012 if (GetNextPacket() < 0)
3017 if (packet->stream_index == videoStream) {
3020 fps_index = int(video_seconds);
3023 if (fps_index >= 0 && fps_index < max_fps_index) {
3025 starting_frames_detected++;
3026 frames_per_second[fps_index]++;
3030 all_frames_detected++;
3035 float avg_fps = 30.0;
3036 if (starting_frames_detected > 0 && fps_index > 0) {
3037 avg_fps = float(starting_frames_detected) / std::min(fps_index, max_fps_index);
3041 if (avg_fps < 8.0) {
3050 if (all_frames_detected > 0) {
3064 void FFmpegReader::RemoveAVFrame(AVFrame *remove_frame) {
3068 av_freep(&remove_frame->data[0]);
3076 void FFmpegReader::RemoveAVPacket(AVPacket *remove_packet) {
3081 delete remove_packet;
3096 root[
"type"] =
"FFmpegReader";
3097 root[
"path"] =
path;
3098 switch (duration_strategy) {
3100 root[
"duration_strategy"] =
"VideoPreferred";
3103 root[
"duration_strategy"] =
"AudioPreferred";
3107 root[
"duration_strategy"] =
"LongestStream";
3124 catch (
const std::exception& e) {
3126 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
3137 if (!root[
"path"].isNull())
3138 path = root[
"path"].asString();
3139 if (!root[
"duration_strategy"].isNull()) {
3140 const std::string strategy = root[
"duration_strategy"].asString();
3141 if (strategy ==
"VideoPreferred") {
3143 }
else if (strategy ==
"AudioPreferred") {