27 #define ENABLE_VAAPI 0
30 #define MAX_SUPPORTED_WIDTH 1950
31 #define MAX_SUPPORTED_HEIGHT 1100
34 #include "libavutil/hwcontext_vaapi.h"
36 typedef struct VAAPIDecodeContext {
38 VAEntrypoint va_entrypoint;
40 VAContextID va_context;
42 #if FF_API_STRUCT_VAAPI_CONTEXT
45 struct vaapi_context *old_context;
46 AVBufferRef *device_ref;
50 AVHWDeviceContext *device;
51 AVVAAPIDeviceContext *hwctx;
53 AVHWFramesContext *frames;
54 AVVAAPIFramesContext *hwfc;
56 enum AVPixelFormat surface_format;
59 #endif // ENABLE_VAAPI
60 #endif // USE_HW_ACCEL
72 : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), NO_PTS_OFFSET(-99999),
73 path(
path), is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true), is_open(false),
74 seek_audio_frame_found(0), seek_video_frame_found(0),is_duration_known(false), largest_frame_processed(0),
76 video_pts(0), pFormatCtx(NULL), videoStream(-1), audioStream(-1), pCodecCtx(NULL), aCodecCtx(NULL),
77 pStream(NULL), aStream(NULL), pFrame(NULL), previous_packet_location{-1,0},
85 pts_offset_seconds = NO_PTS_OFFSET;
86 video_pts_seconds = NO_PTS_OFFSET;
87 audio_pts_seconds = NO_PTS_OFFSET;
90 working_cache.SetMaxBytesFromInfo(max_concurrent_frames * info.fps.ToDouble() * 2, info.width, info.height, info.sample_rate, info.channels);
91 final_cache.SetMaxBytesFromInfo(max_concurrent_frames * 2, info.width, info.height, info.sample_rate, info.channels);
116 if (abs(diff) <= amount)
127 static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx,
const enum AVPixelFormat *pix_fmts)
129 const enum AVPixelFormat *p;
131 for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
133 #if defined(__linux__)
135 case AV_PIX_FMT_VAAPI:
140 case AV_PIX_FMT_VDPAU:
148 case AV_PIX_FMT_DXVA2_VLD:
153 case AV_PIX_FMT_D3D11:
159 #if defined(__APPLE__)
161 case AV_PIX_FMT_VIDEOTOOLBOX:
168 case AV_PIX_FMT_CUDA:
184 return AV_PIX_FMT_NONE;
187 int FFmpegReader::IsHardwareDecodeSupported(
int codecid)
191 case AV_CODEC_ID_H264:
192 case AV_CODEC_ID_MPEG2VIDEO:
193 case AV_CODEC_ID_VC1:
194 case AV_CODEC_ID_WMV1:
195 case AV_CODEC_ID_WMV2:
196 case AV_CODEC_ID_WMV3:
205 #endif // USE_HW_ACCEL
211 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
221 if (avformat_open_input(&pFormatCtx,
path.c_str(), NULL, NULL) != 0)
225 if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
232 packet_status.
reset(
true);
235 for (
unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
237 if (
AV_GET_CODEC_TYPE(pFormatCtx->streams[i]) == AVMEDIA_TYPE_VIDEO && videoStream < 0) {
244 if (
AV_GET_CODEC_TYPE(pFormatCtx->streams[i]) == AVMEDIA_TYPE_AUDIO && audioStream < 0) {
251 if (videoStream == -1 && audioStream == -1)
255 if (videoStream != -1) {
260 pStream = pFormatCtx->streams[videoStream];
266 const AVCodec *pCodec = avcodec_find_decoder(codecId);
267 AVDictionary *
opts = NULL;
268 int retry_decode_open = 2;
273 if (
hw_de_on && (retry_decode_open==2)) {
275 hw_de_supported = IsHardwareDecodeSupported(pCodecCtx->codec_id);
278 retry_decode_open = 0;
283 if (pCodec == NULL) {
284 throw InvalidCodec(
"A valid video codec could not be found for this file.",
path);
288 av_dict_set(&
opts,
"strict",
"experimental", 0);
292 int i_decoder_hw = 0;
294 char *adapter_ptr = NULL;
297 fprintf(stderr,
"Hardware decoding device number: %d\n", adapter_num);
300 pCodecCtx->get_format = get_hw_dec_format;
302 if (adapter_num < 3 && adapter_num >=0) {
303 #if defined(__linux__)
304 snprintf(adapter,
sizeof(adapter),
"/dev/dri/renderD%d", adapter_num+128);
305 adapter_ptr = adapter;
307 switch (i_decoder_hw) {
309 hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
312 hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA;
315 hw_de_av_device_type = AV_HWDEVICE_TYPE_VDPAU;
318 hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
321 hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
325 #elif defined(_WIN32)
328 switch (i_decoder_hw) {
330 hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA;
333 hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2;
336 hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA;
339 hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
342 hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2;
345 #elif defined(__APPLE__)
348 switch (i_decoder_hw) {
350 hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
353 hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
356 hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
366 #if defined(__linux__)
367 if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) {
368 #elif defined(_WIN32)
369 if( adapter_ptr != NULL ) {
370 #elif defined(__APPLE__)
371 if( adapter_ptr != NULL ) {
380 hw_device_ctx = NULL;
382 if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) {
383 if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) {
418 #endif // USE_HW_ACCEL
425 pCodecCtx->thread_type &= ~FF_THREAD_FRAME;
429 int avcodec_return = avcodec_open2(pCodecCtx, pCodec, &
opts);
430 if (avcodec_return < 0) {
431 std::stringstream avcodec_error_msg;
432 avcodec_error_msg <<
"A video codec was found, but could not be opened. Error: " << av_err2string(avcodec_return);
438 AVHWFramesConstraints *constraints = NULL;
439 void *hwconfig = NULL;
440 hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx);
444 ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config;
445 constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig);
446 #endif // ENABLE_VAAPI
448 if (pCodecCtx->coded_width < constraints->min_width ||
449 pCodecCtx->coded_height < constraints->min_height ||
450 pCodecCtx->coded_width > constraints->max_width ||
451 pCodecCtx->coded_height > constraints->max_height) {
454 retry_decode_open = 1;
457 av_buffer_unref(&hw_device_ctx);
458 hw_device_ctx = NULL;
463 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);
464 retry_decode_open = 0;
466 av_hwframe_constraints_free(&constraints);
479 if (pCodecCtx->coded_width < 0 ||
480 pCodecCtx->coded_height < 0 ||
481 pCodecCtx->coded_width > max_w ||
482 pCodecCtx->coded_height > max_h ) {
483 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);
485 retry_decode_open = 1;
488 av_buffer_unref(&hw_device_ctx);
489 hw_device_ctx = NULL;
493 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);
494 retry_decode_open = 0;
502 retry_decode_open = 0;
503 #endif // USE_HW_ACCEL
504 }
while (retry_decode_open);
513 if (audioStream != -1) {
518 aStream = pFormatCtx->streams[audioStream];
524 const AVCodec *aCodec = avcodec_find_decoder(codecId);
530 if (aCodec == NULL) {
531 throw InvalidCodec(
"A valid audio codec could not be found for this file.",
path);
535 AVDictionary *
opts = NULL;
536 av_dict_set(&
opts,
"strict",
"experimental", 0);
539 if (avcodec_open2(aCodecCtx, aCodec, &
opts) < 0)
540 throw InvalidCodec(
"An audio codec was found, but could not be opened.",
path);
550 AVDictionaryEntry *tag = NULL;
551 while ((tag = av_dict_get(pFormatCtx->metadata,
"", tag, AV_DICT_IGNORE_SUFFIX))) {
552 QString str_key = tag->key;
553 QString str_value = tag->value;
554 info.
metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
558 for (
unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
559 AVStream* st = pFormatCtx->streams[i];
560 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
562 for (
int j = 0; j < st->nb_side_data; j++) {
563 AVPacketSideData *sd = &st->side_data[j];
566 if (sd->type == AV_PKT_DATA_DISPLAYMATRIX &&
567 sd->size >= 9 *
sizeof(int32_t) &&
570 double rotation = -av_display_rotation_get(
571 reinterpret_cast<int32_t *
>(sd->data));
572 if (std::isnan(rotation)) rotation = 0;
576 else if (sd->type == AV_PKT_DATA_SPHERICAL) {
581 const AVSphericalMapping* map =
582 reinterpret_cast<const AVSphericalMapping*
>(sd->data);
585 const char* proj_name = av_spherical_projection_name(map->projection);
591 auto to_deg = [](int32_t v){
592 return (
double)v / 65536.0;
594 info.
metadata[
"spherical_yaw"] = std::to_string(to_deg(map->yaw));
595 info.
metadata[
"spherical_pitch"] = std::to_string(to_deg(map->pitch));
596 info.
metadata[
"spherical_roll"] = std::to_string(to_deg(map->roll));
604 previous_packet_location.
frame = -1;
636 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
642 AVPacket *recent_packet = packet;
647 int max_attempts = 128;
652 "attempts", attempts);
664 RemoveAVPacket(recent_packet);
669 if(avcodec_is_open(pCodecCtx)) {
670 avcodec_flush_buffers(pCodecCtx);
676 av_buffer_unref(&hw_device_ctx);
677 hw_device_ctx = NULL;
680 #endif // USE_HW_ACCEL
685 if(avcodec_is_open(aCodecCtx)) {
686 avcodec_flush_buffers(aCodecCtx);
693 working_cache.
Clear();
696 avformat_close_input(&pFormatCtx);
697 av_freep(&pFormatCtx);
702 largest_frame_processed = 0;
703 seek_audio_frame_found = 0;
704 seek_video_frame_found = 0;
705 current_video_frame = 0;
706 last_video_frame.reset();
710 bool FFmpegReader::HasAlbumArt() {
714 return pFormatCtx && videoStream >= 0 && pFormatCtx->streams[videoStream]
715 && (pFormatCtx->streams[videoStream]->disposition & AV_DISPOSITION_ATTACHED_PIC);
718 void FFmpegReader::UpdateAudioInfo() {
735 info.
file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
766 if (aStream->duration > 0 && aStream->duration >
info.
duration) {
769 }
else if (pFormatCtx->duration > 0 &&
info.
duration <= 0.0f) {
771 info.
duration = float(pFormatCtx->duration) / AV_TIME_BASE;
814 AVDictionaryEntry *tag = NULL;
815 while ((tag = av_dict_get(aStream->metadata,
"", tag, AV_DICT_IGNORE_SUFFIX))) {
816 QString str_key = tag->key;
817 QString str_value = tag->value;
818 info.
metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
822 void FFmpegReader::UpdateVideoInfo() {
830 info.
file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
837 AVRational framerate = av_guess_frame_rate(pFormatCtx, pStream, NULL);
849 if (pStream->sample_aspect_ratio.num != 0) {
872 if (!check_interlace) {
873 check_interlace =
true;
875 switch(field_order) {
876 case AV_FIELD_PROGRESSIVE:
889 case AV_FIELD_UNKNOWN:
891 check_interlace =
false;
906 if (
info.
duration <= 0.0f && pFormatCtx->duration >= 0) {
908 info.
duration = float(pFormatCtx->duration) / AV_TIME_BASE;
918 if (
info.
duration <= 0.0f && pStream->duration == AV_NOPTS_VALUE && pFormatCtx->duration == AV_NOPTS_VALUE) {
932 if (pFormatCtx && pFormatCtx->iformat && strcmp(pFormatCtx->iformat->name,
"gif") == 0)
934 if (pStream->nb_frames > 1) {
949 is_duration_known =
false;
952 is_duration_known =
true;
962 AVDictionaryEntry *tag = NULL;
963 while ((tag = av_dict_get(pStream->metadata,
"", tag, AV_DICT_IGNORE_SUFFIX))) {
964 QString str_key = tag->key;
965 QString str_value = tag->value;
966 info.
metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
971 return this->is_duration_known;
977 throw ReaderClosed(
"The FFmpegReader is closed. Call Open() before calling this method.",
path);
980 if (requested_frame < 1)
986 throw InvalidFile(
"Could not detect the duration of the video or audio stream.",
path);
1002 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
1016 int64_t diff = requested_frame - last_frame;
1017 if (diff >= 1 && diff <= 20) {
1019 frame = ReadStream(requested_frame);
1024 Seek(requested_frame);
1033 frame = ReadStream(requested_frame);
1041 std::shared_ptr<Frame> FFmpegReader::ReadStream(int64_t requested_frame) {
1043 bool check_seek =
false;
1044 int packet_error = -1;
1054 CheckWorkingFrames(requested_frame);
1059 if (is_cache_found) {
1063 if (!hold_packet || !packet) {
1065 packet_error = GetNextPacket();
1066 if (packet_error < 0 && !packet) {
1077 check_seek = CheckSeek(
false);
1089 if ((
info.
has_video && packet && packet->stream_index == videoStream) ||
1093 ProcessVideoPacket(requested_frame);
1096 if ((
info.
has_audio && packet && packet->stream_index == audioStream) ||
1100 ProcessAudioPacket(requested_frame);
1105 if ((!
info.
has_video && packet && packet->stream_index == videoStream) ||
1106 (!
info.
has_audio && packet && packet->stream_index == audioStream)) {
1108 if (packet->stream_index == videoStream) {
1110 }
else if (packet->stream_index == audioStream) {
1116 RemoveAVPacket(packet);
1126 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);
1143 "largest_frame_processed", largest_frame_processed,
1144 "Working Cache Count", working_cache.
Count());
1153 CheckWorkingFrames(requested_frame);
1169 std::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
1172 if (!frame->has_image_data) {
1177 frame->AddAudioSilence(samples_in_frame);
1182 std::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
1184 f->AddAudioSilence(samples_in_frame);
1192 int FFmpegReader::GetNextPacket() {
1193 int found_packet = 0;
1194 AVPacket *next_packet;
1195 next_packet =
new AVPacket();
1196 found_packet = av_read_frame(pFormatCtx, next_packet);
1200 RemoveAVPacket(packet);
1203 if (found_packet >= 0) {
1205 packet = next_packet;
1208 if (packet->stream_index == videoStream) {
1210 }
else if (packet->stream_index == audioStream) {
1219 return found_packet;
1223 bool FFmpegReader::GetAVFrame() {
1224 int frameFinished = 0;
1230 int send_packet_err = 0;
1231 int64_t send_packet_pts = 0;
1232 if ((packet && packet->stream_index == videoStream) || !packet) {
1233 send_packet_err = avcodec_send_packet(pCodecCtx, packet);
1235 if (packet && send_packet_err >= 0) {
1236 send_packet_pts = GetPacketPTS();
1237 hold_packet =
false;
1246 #endif // USE_HW_ACCEL
1247 if (send_packet_err < 0 && send_packet_err != AVERROR_EOF) {
1248 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);
1249 if (send_packet_err == AVERROR(EAGAIN)) {
1251 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::GetAVFrame (send packet: AVERROR(EAGAIN): user must read output with avcodec_receive_frame()",
"send_packet_pts", send_packet_pts);
1253 if (send_packet_err == AVERROR(EINVAL)) {
1254 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);
1256 if (send_packet_err == AVERROR(ENOMEM)) {
1257 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);
1264 int receive_frame_err = 0;
1265 AVFrame *next_frame2;
1271 #endif // USE_HW_ACCEL
1273 next_frame2 = next_frame;
1276 while (receive_frame_err >= 0) {
1277 receive_frame_err = avcodec_receive_frame(pCodecCtx, next_frame2);
1279 if (receive_frame_err != 0) {
1280 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);
1282 if (receive_frame_err == AVERROR_EOF) {
1284 "FFmpegReader::GetAVFrame (receive frame: AVERROR_EOF: EOF detected from decoder, flushing buffers)",
"send_packet_pts", send_packet_pts);
1285 avcodec_flush_buffers(pCodecCtx);
1288 if (receive_frame_err == AVERROR(EINVAL)) {
1290 "FFmpegReader::GetAVFrame (receive frame: AVERROR(EINVAL): invalid frame received, flushing buffers)",
"send_packet_pts", send_packet_pts);
1291 avcodec_flush_buffers(pCodecCtx);
1293 if (receive_frame_err == AVERROR(EAGAIN)) {
1295 "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);
1297 if (receive_frame_err == AVERROR_INPUT_CHANGED) {
1299 "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);
1310 if (next_frame2->format == hw_de_av_pix_fmt) {
1311 next_frame->format = AV_PIX_FMT_YUV420P;
1312 if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) {
1315 if ((err = av_frame_copy_props(next_frame,next_frame2)) < 0) {
1321 #endif // USE_HW_ACCEL
1323 next_frame = next_frame2;
1335 av_image_copy(pFrame->data, pFrame->linesize, (
const uint8_t**)next_frame->data, next_frame->linesize,
1342 if (next_frame->pts != AV_NOPTS_VALUE) {
1345 video_pts = next_frame->pts;
1346 }
else if (next_frame->pkt_dts != AV_NOPTS_VALUE) {
1348 video_pts = next_frame->pkt_dts;
1352 "FFmpegReader::GetAVFrame (Successful frame received)",
"video_pts", video_pts,
"send_packet_pts", send_packet_pts);
1361 #endif // USE_HW_ACCEL
1363 avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);
1369 if (frameFinished) {
1373 av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt,
info.
width,
1376 #endif // IS_FFMPEG_3_2
1382 return frameFinished;
1386 bool FFmpegReader::CheckSeek(
bool is_video) {
1391 if ((is_video_seek && !seek_video_frame_found) || (!is_video_seek && !seek_audio_frame_found))
1399 int64_t max_seeked_frame = std::max(seek_audio_frame_found, seek_video_frame_found);
1402 if (max_seeked_frame >= seeking_frame) {
1405 "is_video_seek", is_video_seek,
1406 "max_seeked_frame", max_seeked_frame,
1407 "seeking_frame", seeking_frame,
1408 "seeking_pts", seeking_pts,
1409 "seek_video_frame_found", seek_video_frame_found,
1410 "seek_audio_frame_found", seek_audio_frame_found);
1413 Seek(seeking_frame - (10 * seek_count * seek_count));
1417 "is_video_seek", is_video_seek,
1418 "packet->pts", GetPacketPTS(),
1419 "seeking_pts", seeking_pts,
1420 "seeking_frame", seeking_frame,
1421 "seek_video_frame_found", seek_video_frame_found,
1422 "seek_audio_frame_found", seek_audio_frame_found);
1436 void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) {
1439 int frame_finished = GetAVFrame();
1442 if (!frame_finished) {
1445 RemoveAVFrame(pFrame);
1451 int64_t current_frame = ConvertVideoPTStoFrame(video_pts);
1454 if (!seek_video_frame_found && is_seeking)
1455 seek_video_frame_found = current_frame;
1461 working_cache.
Add(CreateFrame(requested_frame));
1473 AVFrame *pFrameRGB =
nullptr;
1474 uint8_t *buffer =
nullptr;
1478 if (pFrameRGB ==
nullptr)
1500 max_width = std::max(
float(max_width), max_width * max_scale_x);
1501 max_height = std::max(
float(max_height), max_height * max_scale_y);
1507 QSize width_size(max_width * max_scale_x,
1510 max_height * max_scale_y);
1512 if (width_size.width() >= max_width && width_size.height() >= max_height) {
1513 max_width = std::max(max_width, width_size.width());
1514 max_height = std::max(max_height, width_size.height());
1516 max_width = std::max(max_width, height_size.width());
1517 max_height = std::max(max_height, height_size.height());
1524 float preview_ratio = 1.0;
1531 max_width =
info.
width * max_scale_x * preview_ratio;
1532 max_height =
info.
height * max_scale_y * preview_ratio;
1537 int original_height = height;
1538 if (max_width != 0 && max_height != 0 && max_width < width && max_height < height) {
1540 float ratio = float(width) / float(height);
1541 int possible_width = round(max_height * ratio);
1542 int possible_height = round(max_width / ratio);
1544 if (possible_width <= max_width) {
1546 width = possible_width;
1547 height = max_height;
1551 height = possible_height;
1556 const int bytes_per_pixel = 4;
1557 int buffer_size = (width * height * bytes_per_pixel) + 128;
1558 buffer =
new unsigned char[buffer_size]();
1563 int scale_mode = SWS_FAST_BILINEAR;
1565 scale_mode = SWS_BICUBIC;
1571 sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,
1572 original_height, pFrameRGB->data, pFrameRGB->linesize);
1575 std::shared_ptr<Frame> f = CreateFrame(current_frame);
1580 f->AddImage(width, height, bytes_per_pixel, QImage::Format_RGBA8888_Premultiplied, buffer);
1583 f->AddImage(width, height, bytes_per_pixel, QImage::Format_RGBA8888, buffer);
1587 working_cache.
Add(f);
1590 last_video_frame = f;
1596 RemoveAVFrame(pFrame);
1597 sws_freeContext(img_convert_ctx);
1603 ZmqLogger::Instance()->
AppendDebugMethod(
"FFmpegReader::ProcessVideoPacket (After)",
"requested_frame", requested_frame,
"current_frame", current_frame,
"f->number", f->number,
"video_pts_seconds", video_pts_seconds);
1607 void FFmpegReader::ProcessAudioPacket(int64_t requested_frame) {
1610 if (packet && packet->pts != AV_NOPTS_VALUE) {
1612 location = GetAudioPTSLocation(packet->pts);
1615 if (!seek_audio_frame_found && is_seeking)
1616 seek_audio_frame_found = location.
frame;
1623 working_cache.
Add(CreateFrame(requested_frame));
1627 "requested_frame", requested_frame,
1628 "target_frame", location.
frame,
1632 int frame_finished = 0;
1636 int packet_samples = 0;
1640 int send_packet_err = avcodec_send_packet(aCodecCtx, packet);
1641 if (send_packet_err < 0 && send_packet_err != AVERROR_EOF) {
1645 int receive_frame_err = avcodec_receive_frame(aCodecCtx, audio_frame);
1646 if (receive_frame_err >= 0) {
1649 if (receive_frame_err == AVERROR_EOF) {
1653 if (receive_frame_err == AVERROR(EINVAL) || receive_frame_err == AVERROR_EOF) {
1655 avcodec_flush_buffers(aCodecCtx);
1657 if (receive_frame_err != 0) {
1662 int used = avcodec_decode_audio4(aCodecCtx, audio_frame, &frame_finished, packet);
1665 if (frame_finished) {
1671 audio_pts = audio_frame->pts;
1674 location = GetAudioPTSLocation(audio_pts);
1677 int plane_size = -1;
1683 data_size = av_samples_get_buffer_size(&plane_size, nb_channels,
1687 packet_samples = audio_frame->nb_samples * nb_channels;
1696 int pts_remaining_samples = packet_samples /
info.
channels;
1699 if (pts_remaining_samples == 0) {
1701 "packet_samples", packet_samples,
1703 "pts_remaining_samples", pts_remaining_samples);
1707 while (pts_remaining_samples) {
1712 int samples = samples_per_frame - previous_packet_location.
sample_start;
1713 if (samples > pts_remaining_samples)
1714 samples = pts_remaining_samples;
1717 pts_remaining_samples -= samples;
1719 if (pts_remaining_samples > 0) {
1721 previous_packet_location.
frame++;
1730 "packet_samples", packet_samples,
1738 audio_converted->nb_samples = audio_frame->nb_samples;
1739 av_samples_alloc(audio_converted->data, audio_converted->linesize,
info.
channels, audio_frame->nb_samples, AV_SAMPLE_FMT_FLTP, 0);
1755 av_opt_set_int(avr,
"out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
1762 audio_converted->data,
1763 audio_converted->linesize[0],
1764 audio_converted->nb_samples,
1766 audio_frame->linesize[0],
1767 audio_frame->nb_samples);
1774 int64_t starting_frame_number = -1;
1775 for (
int channel_filter = 0; channel_filter <
info.
channels; channel_filter++) {
1777 starting_frame_number = location.
frame;
1778 int channel_buffer_size = nb_samples;
1779 auto *channel_buffer = (
float *) (audio_converted->data[channel_filter]);
1783 int remaining_samples = channel_buffer_size;
1784 while (remaining_samples > 0) {
1789 int samples = std::fmin(samples_per_frame - start, remaining_samples);
1792 std::shared_ptr<Frame> f = CreateFrame(starting_frame_number);
1795 f->AddAudio(
true, channel_filter, start, channel_buffer, samples, 1.0f);
1799 "frame", starting_frame_number,
1802 "channel", channel_filter,
1803 "samples_per_frame", samples_per_frame);
1806 working_cache.
Add(f);
1809 remaining_samples -= samples;
1812 if (remaining_samples > 0)
1813 channel_buffer += samples;
1816 starting_frame_number++;
1824 av_free(audio_converted->data[0]);
1833 "requested_frame", requested_frame,
1834 "starting_frame", location.
frame,
1835 "end_frame", starting_frame_number - 1,
1836 "audio_pts_seconds", audio_pts_seconds);
1842 void FFmpegReader::Seek(int64_t requested_frame) {
1844 if (requested_frame < 1)
1845 requested_frame = 1;
1848 if (requested_frame > largest_frame_processed && packet_status.
end_of_file) {
1855 "requested_frame", requested_frame,
1856 "seek_count", seek_count,
1857 "last_frame", last_frame);
1860 working_cache.
Clear();
1864 video_pts_seconds = NO_PTS_OFFSET;
1866 audio_pts_seconds = NO_PTS_OFFSET;
1867 hold_packet =
false;
1869 current_video_frame = 0;
1870 largest_frame_processed = 0;
1875 packet_status.
reset(
false);
1881 int buffer_amount = std::max(max_concurrent_frames, 8);
1882 if (requested_frame - buffer_amount < 20) {
1896 if (seek_count == 1) {
1899 seeking_pts = ConvertFrameToVideoPTS(1);
1901 seek_audio_frame_found = 0;
1902 seek_video_frame_found = 0;
1906 bool seek_worked =
false;
1907 int64_t seek_target = 0;
1911 seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount);
1913 fprintf(stderr,
"%s: error while seeking video stream\n", pFormatCtx->AV_FILENAME);
1916 is_video_seek =
true;
1923 seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount);
1925 fprintf(stderr,
"%s: error while seeking audio stream\n", pFormatCtx->AV_FILENAME);
1928 is_video_seek =
false;
1937 avcodec_flush_buffers(aCodecCtx);
1941 avcodec_flush_buffers(pCodecCtx);
1944 previous_packet_location.
frame = -1;
1949 if (seek_count == 1) {
1951 seeking_pts = seek_target;
1952 seeking_frame = requested_frame;
1954 seek_audio_frame_found = 0;
1955 seek_video_frame_found = 0;
1983 int64_t FFmpegReader::GetPacketPTS() {
1985 int64_t current_pts = packet->pts;
1986 if (current_pts == AV_NOPTS_VALUE && packet->dts != AV_NOPTS_VALUE)
1987 current_pts = packet->dts;
1993 return AV_NOPTS_VALUE;
1998 void FFmpegReader::UpdatePTSOffset() {
1999 if (pts_offset_seconds != NO_PTS_OFFSET) {
2003 pts_offset_seconds = 0.0;
2004 double video_pts_offset_seconds = 0.0;
2005 double audio_pts_offset_seconds = 0.0;
2007 bool has_video_pts =
false;
2010 has_video_pts =
true;
2012 bool has_audio_pts =
false;
2015 has_audio_pts =
true;
2019 while (!has_video_pts || !has_audio_pts) {
2021 if (GetNextPacket() < 0)
2026 int64_t pts = GetPacketPTS();
2029 if (!has_video_pts && packet->stream_index == videoStream) {
2035 if (std::abs(video_pts_offset_seconds) <= 10.0) {
2036 has_video_pts =
true;
2039 else if (!has_audio_pts && packet->stream_index == audioStream) {
2045 if (std::abs(audio_pts_offset_seconds) <= 10.0) {
2046 has_audio_pts =
true;
2052 if (has_video_pts && has_audio_pts) {
2064 pts_offset_seconds = std::max(video_pts_offset_seconds, audio_pts_offset_seconds);
2069 int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) {
2071 int64_t previous_video_frame = current_video_frame;
2080 if (current_video_frame == 0)
2081 current_video_frame = frame;
2085 if (frame == previous_video_frame) {
2090 current_video_frame++;
2099 int64_t FFmpegReader::ConvertFrameToVideoPTS(int64_t frame_number) {
2101 double seconds = (double(frame_number - 1) /
info.
fps.
ToDouble()) + pts_offset_seconds;
2111 int64_t FFmpegReader::ConvertFrameToAudioPTS(int64_t frame_number) {
2113 double seconds = (double(frame_number - 1) /
info.
fps.
ToDouble()) + pts_offset_seconds;
2123 AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) {
2131 int64_t whole_frame = int64_t(frame);
2134 double sample_start_percentage = frame - double(whole_frame);
2140 int sample_start = round(
double(samples_per_frame) * sample_start_percentage);
2143 if (whole_frame < 1)
2145 if (sample_start < 0)
2152 if (previous_packet_location.
frame != -1) {
2153 if (location.
is_near(previous_packet_location, samples_per_frame, samples_per_frame)) {
2154 int64_t orig_frame = location.
frame;
2159 location.
frame = previous_packet_location.
frame;
2162 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);
2171 previous_packet_location = location;
2178 std::shared_ptr<Frame> FFmpegReader::CreateFrame(int64_t requested_frame) {
2180 std::shared_ptr<Frame> output = working_cache.
GetFrame(requested_frame);
2184 output = working_cache.
GetFrame(requested_frame);
2185 if(output)
return output;
2193 working_cache.
Add(output);
2196 if (requested_frame > largest_frame_processed)
2197 largest_frame_processed = requested_frame;
2204 bool FFmpegReader::IsPartialFrame(int64_t requested_frame) {
2207 bool seek_trash =
false;
2208 int64_t max_seeked_frame = seek_audio_frame_found;
2209 if (seek_video_frame_found > max_seeked_frame) {
2210 max_seeked_frame = seek_video_frame_found;
2212 if ((
info.
has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) ||
2213 (
info.
has_video && seek_video_frame_found && max_seeked_frame >= requested_frame)) {
2221 void FFmpegReader::CheckWorkingFrames(int64_t requested_frame) {
2224 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
2227 std::vector<std::shared_ptr<openshot::Frame>> working_frames = working_cache.
GetFrames();
2228 std::vector<std::shared_ptr<openshot::Frame>>::iterator working_itr;
2231 for(working_itr = working_frames.begin(); working_itr != working_frames.end(); ++working_itr)
2234 std::shared_ptr<Frame> f = *working_itr;
2237 if (!f || f->number > requested_frame) {
2243 double frame_pts_seconds = (double(f->number - 1) /
info.
fps.
ToDouble()) + pts_offset_seconds;
2244 double recent_pts_seconds = std::max(video_pts_seconds, audio_pts_seconds);
2247 bool is_video_ready =
false;
2248 bool is_audio_ready =
false;
2249 double recent_pts_diff = recent_pts_seconds - frame_pts_seconds;
2250 if ((frame_pts_seconds <= video_pts_seconds)
2251 || (recent_pts_diff > 1.5)
2255 is_video_ready =
true;
2257 "frame_number", f->number,
2258 "frame_pts_seconds", frame_pts_seconds,
2259 "video_pts_seconds", video_pts_seconds,
2260 "recent_pts_diff", recent_pts_diff);
2264 for (int64_t previous_frame = requested_frame - 1; previous_frame > 0; previous_frame--) {
2266 if (previous_frame_instance && previous_frame_instance->has_image_data) {
2268 f->AddImage(std::make_shared<QImage>(previous_frame_instance->GetImage()->copy()));
2273 if (last_video_frame && !f->has_image_data) {
2275 f->AddImage(std::make_shared<QImage>(last_video_frame->GetImage()->copy()));
2276 }
else if (!f->has_image_data) {
2277 f->AddColor(
"#000000");
2282 double audio_pts_diff = audio_pts_seconds - frame_pts_seconds;
2283 if ((frame_pts_seconds < audio_pts_seconds && audio_pts_diff > 1.0)
2284 || (recent_pts_diff > 1.5)
2289 is_audio_ready =
true;
2291 "frame_number", f->number,
2292 "frame_pts_seconds", frame_pts_seconds,
2293 "audio_pts_seconds", audio_pts_seconds,
2294 "audio_pts_diff", audio_pts_diff,
2295 "recent_pts_diff", recent_pts_diff);
2297 bool is_seek_trash = IsPartialFrame(f->number);
2305 "frame_number", f->number,
2306 "is_video_ready", is_video_ready,
2307 "is_audio_ready", is_audio_ready,
2313 if ((!packet_status.
end_of_file && is_video_ready && is_audio_ready) || packet_status.
end_of_file || is_seek_trash) {
2316 "requested_frame", requested_frame,
2317 "f->number", f->number,
2318 "is_seek_trash", is_seek_trash,
2319 "Working Cache Count", working_cache.
Count(),
2323 if (!is_seek_trash) {
2328 working_cache.
Remove(f->number);
2331 last_frame = f->number;
2334 working_cache.
Remove(f->number);
2341 working_frames.clear();
2342 working_frames.shrink_to_fit();
2346 void FFmpegReader::CheckFPS() {
2354 int frames_per_second[3] = {0,0,0};
2355 int max_fps_index =
sizeof(frames_per_second) /
sizeof(frames_per_second[0]);
2358 int all_frames_detected = 0;
2359 int starting_frames_detected = 0;
2364 if (GetNextPacket() < 0)
2369 if (packet->stream_index == videoStream) {
2372 fps_index = int(video_seconds);
2375 if (fps_index >= 0 && fps_index < max_fps_index) {
2377 starting_frames_detected++;
2378 frames_per_second[fps_index]++;
2382 all_frames_detected++;
2387 float avg_fps = 30.0;
2388 if (starting_frames_detected > 0 && fps_index > 0) {
2389 avg_fps = float(starting_frames_detected) / std::min(fps_index, max_fps_index);
2393 if (avg_fps < 8.0) {
2402 if (all_frames_detected > 0) {
2416 void FFmpegReader::RemoveAVFrame(AVFrame *remove_frame) {
2420 av_freep(&remove_frame->data[0]);
2428 void FFmpegReader::RemoveAVPacket(AVPacket *remove_packet) {
2433 delete remove_packet;
2448 root[
"type"] =
"FFmpegReader";
2449 root[
"path"] =
path;
2464 catch (
const std::exception& e) {
2466 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
2477 if (!root[
"path"].isNull())
2478 path = root[
"path"].asString();