31 #include "../include/FFmpegReader.h"
33 using namespace openshot;
36 : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0),
37 audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(
true), check_interlace(
false),
38 check_fps(
false), enable_seek(
true), rescaler_position(0), num_of_rescalers(
OPEN_MP_NUM_PROCESSORS), is_open(
false),
39 seek_audio_frame_found(0), seek_video_frame_found(0), prev_samples(0), prev_pts(0),
40 pts_total(0), pts_counter(0), is_duration_known(
false), largest_frame_processed(0),
41 current_video_frame(0), has_missing_frames(
false), num_packets_since_video_frame(0), num_checks_since_final(0) {
45 avcodec_register_all();
48 working_cache.SetMaxBytesFromInfo(
OPEN_MP_NUM_PROCESSORS * 60, info.width, info.height, info.sample_rate, info.channels);
49 final_cache.SetMaxBytesFromInfo(
OPEN_MP_NUM_PROCESSORS * 4, info.width, info.height, info.sample_rate, info.channels);
63 void FFmpegReader::InitScalers()
66 for (
int x = 0; x < num_of_rescalers; x++)
72 image_rescalers.push_back(img_convert_ctx);
85 if (location.
frame ==
frame && sample_diff >= 0 && sample_diff <= amount)
94 if (sample_diff >= 0 && sample_diff <= amount)
103 if (sample_diff >= 0 && sample_diff <= amount)
112 void FFmpegReader::RemoveScalers()
115 for (
int x = 0; x < num_of_rescalers; x++)
116 sws_freeContext(image_rescalers[x]);
119 image_rescalers.clear();
131 if (avformat_open_input(&pFormatCtx, path.c_str(), NULL, NULL) != 0)
132 throw InvalidFile(
"File could not be opened.", path);
135 if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
136 throw NoStreamsFound(
"No streams found in file.", path);
141 for (
unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
144 if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && videoStream < 0) {
148 if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audioStream < 0) {
152 if (videoStream == -1 && audioStream == -1)
153 throw NoStreamsFound(
"No video or audio streams found in this file.", path);
156 if (videoStream != -1)
162 pStream = pFormatCtx->streams[videoStream];
163 pCodecCtx = pFormatCtx->streams[videoStream]->codec;
169 AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
170 if (pCodec == NULL) {
171 throw InvalidCodec(
"A valid video codec could not be found for this file.", path);
174 if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
175 throw InvalidCodec(
"A video codec was found, but could not be opened.", path);
185 if (audioStream != -1)
191 aStream = pFormatCtx->streams[audioStream];
192 aCodecCtx = pFormatCtx->streams[audioStream]->codec;
198 AVCodec *aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
199 if (aCodec == NULL) {
200 throw InvalidCodec(
"A valid audio codec could not be found for this file.", path);
203 if (avcodec_open2(aCodecCtx, aCodec, NULL) < 0)
204 throw InvalidCodec(
"An audio codec was found, but could not be opened.", path);
211 previous_packet_location.
frame = -1;
237 avcodec_flush_buffers(pCodecCtx);
238 avcodec_close(pCodecCtx);
242 avcodec_flush_buffers(aCodecCtx);
243 avcodec_close(aCodecCtx);
248 working_cache.
Clear();
253 processed_video_frames.clear();
254 processed_audio_frames.clear();
255 processing_video_frames.clear();
256 processing_audio_frames.clear();
257 missing_video_frames.clear();
261 avformat_close_input(&pFormatCtx);
262 av_freep(&pFormatCtx);
266 largest_frame_processed = 0;
267 seek_audio_frame_found = 0;
268 seek_video_frame_found = 0;
269 current_video_frame = 0;
270 has_missing_frames =
false;
274 void FFmpegReader::UpdateAudioInfo()
278 info.
file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
281 if (aCodecCtx->channel_layout == 0)
282 aCodecCtx->channel_layout = av_get_default_channel_layout( aCodecCtx->channels );;
292 if (aStream->duration > 0.0f && aStream->duration >
info.
duration)
318 void FFmpegReader::UpdateVideoInfo()
322 info.
file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
334 if (pStream->sample_aspect_ratio.num != 0)
339 else if (pCodecCtx->sample_aspect_ratio.num != 0)
385 is_duration_known =
false;
390 is_duration_known =
true;
416 throw ReaderClosed(
"The FFmpegReader is closed. Call Open() before calling this method.", path);
419 if (requested_frame < 1)
421 if (requested_frame > info.video_length && is_duration_known)
422 requested_frame = info.video_length;
423 if (info.has_video && info.video_length == 0)
425 throw InvalidFile(
"Could not detect the duration of the video or audio stream.", path);
428 AppendDebugMethod(
"FFmpegReader::GetFrame",
"requested_frame", requested_frame,
"last_frame", last_frame,
"", -1,
"", -1,
"", -1,
"", -1);
431 tr1::shared_ptr<Frame> frame = final_cache.GetFrame(requested_frame);
434 AppendDebugMethod(
"FFmpegReader::GetFrame",
"returned cached frame", requested_frame,
"", -1,
"", -1,
"", -1,
"", -1,
"", -1);
442 const GenericScopedLock<CriticalSection> lock(getFrameCriticalSection);
445 if (has_missing_frames)
446 CheckMissingFrame(requested_frame);
447 frame = final_cache.GetFrame(requested_frame);
450 AppendDebugMethod(
"FFmpegReader::GetFrame",
"returned cached frame on 2nd look", requested_frame,
"", -1,
"", -1,
"", -1,
"", -1,
"", -1);
461 if (last_frame == 0 && requested_frame != 1)
466 long int diff = requested_frame - last_frame;
467 if (diff >= 1 && diff <= 20)
470 return ReadStream(requested_frame);
477 Seek(requested_frame);
479 else if (!enable_seek && diff < 0)
487 return ReadStream(requested_frame);
494 tr1::shared_ptr<Frame> FFmpegReader::ReadStream(
long int requested_frame)
497 bool end_of_stream =
false;
498 bool check_seek =
false;
499 bool frame_finished =
false;
500 int packet_error = -1;
503 int packets_processed = 0;
509 omp_set_nested(
true);
512 AppendDebugMethod(
"FFmpegReader::ReadStream",
"requested_frame", requested_frame,
"OPEN_MP_NUM_PROCESSORS",
OPEN_MP_NUM_PROCESSORS,
"", -1,
"", -1,
"", -1,
"", -1);
522 packet_error = GetNextPacket();
525 while (processing_video_frames.size() + processing_audio_frames.size() >= minimum_packets)
529 if (packet_error < 0)
532 end_of_stream =
true;
537 AppendDebugMethod(
"FFmpegReader::ReadStream (GetNextPacket)",
"requested_frame", requested_frame,
"processing_video_frames.size()", processing_video_frames.size(),
"processing_audio_frames.size()", processing_audio_frames.size(),
"minimum_packets", minimum_packets,
"packets_processed", packets_processed,
"", -1);
540 if (packet->stream_index == videoStream)
543 num_packets_since_video_frame = 0;
547 #pragma omp critical (openshot_seek)
548 check_seek = CheckSeek(
true);
554 RemoveAVPacket(packet);
561 frame_finished = GetAVFrame();
567 UpdatePTSOffset(
true);
570 ProcessVideoPacket(requested_frame);
575 else if (packet->stream_index == audioStream)
578 num_packets_since_video_frame++;
582 #pragma omp critical (openshot_seek)
583 check_seek = CheckSeek(
false);
589 RemoveAVPacket(packet);
596 UpdatePTSOffset(
false);
606 bool is_cache_found =
false;
609 CheckMissingFrame(requested_frame);
612 CheckWorkingFrames(
false, requested_frame);
622 if ((is_cache_found && packets_processed >= minimum_packets))
631 AppendDebugMethod(
"FFmpegReader::ReadStream (Completed)",
"packets_processed", packets_processed,
"end_of_stream", end_of_stream,
"largest_frame_processed", largest_frame_processed,
"Working Cache Count", working_cache.
Count(),
"", -1,
"", -1);
636 CheckWorkingFrames(end_of_stream, requested_frame);
653 tr1::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
662 int FFmpegReader::GetNextPacket()
664 int found_packet = 0;
665 AVPacket *next_packet =
new AVPacket();
666 found_packet = av_read_frame(pFormatCtx, next_packet);
668 if (found_packet >= 0)
670 #pragma omp critical (packet_cache)
673 packets[next_packet] = next_packet;
676 packet = packets[next_packet];
683 av_free_packet(next_packet);
692 bool FFmpegReader::GetAVFrame()
694 int frameFinished = -1;
698 #pragma omp critical (packet_cache)
699 avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);
706 AVPicture *copyFrame =
new AVPicture();
708 av_picture_copy(copyFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt,
info.
width,
info.
height);
710 #pragma omp critical (packet_cache)
713 frames[copyFrame] = copyFrame;
714 pFrame = frames[copyFrame];
718 if (!check_interlace)
720 check_interlace =
true;
729 RemoveAVPacket(packet);
736 return frameFinished;
740 bool FFmpegReader::CheckSeek(
bool is_video)
747 if ((is_video_seek && !seek_video_frame_found) || (!is_video_seek && !seek_audio_frame_found))
755 long int max_seeked_frame = seek_audio_frame_found;
756 if (seek_video_frame_found > max_seeked_frame)
757 max_seeked_frame = seek_video_frame_found;
760 if (max_seeked_frame >= seeking_frame)
763 AppendDebugMethod(
"FFmpegReader::CheckSeek (Too far, seek again)",
"is_video_seek", is_video_seek,
"max_seeked_frame", max_seeked_frame,
"seeking_frame", seeking_frame,
"seeking_pts", seeking_pts,
"seek_video_frame_found", seek_video_frame_found,
"seek_audio_frame_found", seek_audio_frame_found);
766 Seek(seeking_frame - (20 * seek_count * seek_count));
771 AppendDebugMethod(
"FFmpegReader::CheckSeek (Successful)",
"is_video_seek", is_video_seek,
"current_pts", packet->pts,
"seeking_pts", seeking_pts,
"seeking_frame", seeking_frame,
"seek_video_frame_found", seek_video_frame_found,
"seek_audio_frame_found", seek_audio_frame_found);
785 void FFmpegReader::ProcessVideoPacket(
long int requested_frame)
788 long int current_frame = ConvertVideoPTStoFrame(GetVideoPTS());
791 if (!seek_video_frame_found && is_seeking)
792 seek_video_frame_found = current_frame;
795 if ((!has_missing_frames and current_frame < (requested_frame - 20)) or (current_frame == -1))
798 RemoveAVFrame(pFrame);
799 RemoveAVPacket(packet);
802 AppendDebugMethod(
"FFmpegReader::ProcessVideoPacket (Skipped)",
"requested_frame", requested_frame,
"current_frame", current_frame,
"", -1,
"", -1,
"", -1,
"", -1);
809 AppendDebugMethod(
"FFmpegReader::ProcessVideoPacket (Before)",
"requested_frame", requested_frame,
"current_frame", current_frame,
"", -1,
"", -1,
"", -1,
"", -1);
816 AVPacket *my_packet = packets[packet];
817 AVPicture *my_frame = frames[pFrame];
820 SwsContext *img_convert_ctx = image_rescalers[rescaler_position];
822 if (rescaler_position == num_of_rescalers)
823 rescaler_position = 0;
827 processing_video_frames[current_frame] = current_frame;
829 #pragma omp task firstprivate(current_frame, my_packet, my_frame, height, width, video_length, pix_fmt, img_convert_ctx)
832 AVFrame *pFrameRGB = NULL;
834 uint8_t *buffer = NULL;
838 if (pFrameRGB == NULL)
839 throw OutOfBoundsFrame(
"Convert Image Broke!", current_frame, video_length);
842 numBytes = avpicture_get_size(
PIX_FMT_RGBA, width, height);
843 buffer = (uint8_t *) av_malloc(numBytes *
sizeof(uint8_t) * 2);
848 avpicture_fill((AVPicture *) pFrameRGB, buffer,
PIX_FMT_RGBA, width, height);
851 sws_scale(img_convert_ctx, my_frame->data, my_frame->linesize, 0,
852 height, pFrameRGB->data, pFrameRGB->linesize);
855 tr1::shared_ptr<Frame> f = CreateFrame(current_frame);
858 f->AddImage(width, height, 4, QImage::Format_RGBA8888, buffer);
861 working_cache.
Add(f->number, f);
864 last_video_frame = f;
871 RemoveAVFrame(my_frame);
872 RemoveAVPacket(my_packet);
877 processing_video_frames.erase(current_frame);
878 processed_video_frames[current_frame] = current_frame;
882 AppendDebugMethod(
"FFmpegReader::ProcessVideoPacket (After)",
"requested_frame", requested_frame,
"current_frame", current_frame,
"f->number", f->number,
"", -1,
"", -1,
"", -1);
889 void FFmpegReader::ProcessAudioPacket(
long int requested_frame,
long int target_frame,
int starting_sample)
892 if (!seek_audio_frame_found && is_seeking)
893 seek_audio_frame_found = target_frame;
896 if (!has_missing_frames and target_frame < (requested_frame - 20))
899 RemoveAVPacket(packet);
902 AppendDebugMethod(
"FFmpegReader::ProcessAudioPacket (Skipped)",
"requested_frame", requested_frame,
"target_frame", target_frame,
"starting_sample", starting_sample,
"", -1,
"", -1,
"", -1);
909 AVPacket *my_packet = packets[packet];
912 AppendDebugMethod(
"FFmpegReader::ProcessAudioPacket (Before)",
"requested_frame", requested_frame,
"target_frame", target_frame,
"starting_sample", starting_sample,
"", -1,
"", -1,
"", -1);
915 int frame_finished = 0;
919 int packet_samples = 0;
924 int used = avcodec_decode_audio4(aCodecCtx, audio_frame, &frame_finished, my_packet);
926 if (frame_finished) {
929 int planar = av_sample_fmt_is_planar(aCodecCtx->sample_fmt);
931 data_size = av_samples_get_buffer_size(&plane_size,
933 audio_frame->nb_samples,
934 aCodecCtx->sample_fmt, 1);
937 packet_samples = audio_frame->nb_samples * aCodecCtx->channels;
941 int pts_remaining_samples = packet_samples /
info.
channels;
944 int adjusted_pts = packet->pts + audio_pts_offset;
949 AppendDebugMethod(
"FFmpegReader::ProcessAudioPacket (Decode Info A)",
"pts_counter", pts_counter,
"PTS", adjusted_pts,
"Offset", audio_pts_offset,
"PTS Diff", adjusted_pts - prev_pts,
"Samples", pts_remaining_samples,
"Sample PTS ratio",
float(adjusted_pts - prev_pts) / pts_remaining_samples);
950 AppendDebugMethod(
"FFmpegReader::ProcessAudioPacket (Decode Info B)",
"Sample Diff", pts_remaining_samples - prev_samples - prev_pts,
"Total", pts_total,
"PTS Seconds", audio_seconds,
"Sample Seconds", sample_seconds,
"Seconds Diff", audio_seconds - sample_seconds,
"raw samples", packet_samples);
953 prev_pts = adjusted_pts;
954 pts_total += pts_remaining_samples;
956 prev_samples = pts_remaining_samples;
961 processing_audio_frames.insert(pair<int, int>(previous_packet_location.
frame, previous_packet_location.
frame));
964 while (pts_remaining_samples)
970 int samples = samples_per_frame - previous_packet_location.
sample_start;
971 if (samples > pts_remaining_samples)
972 samples = pts_remaining_samples;
975 pts_remaining_samples -= samples;
977 if (pts_remaining_samples > 0) {
979 previous_packet_location.
frame++;
985 processing_audio_frames.insert(pair<int, int>(previous_packet_location.
frame, previous_packet_location.
frame));
998 #pragma omp task firstprivate(requested_frame, target_frame, starting_sample, my_packet, audio_frame)
1003 AppendDebugMethod(
"FFmpegReader::ProcessAudioPacket (ReSample)",
"packet_samples", packet_samples,
"info.channels",
info.
channels,
"info.sample_rate",
info.
sample_rate,
"aCodecCtx->sample_fmt", aCodecCtx->sample_fmt,
"AV_SAMPLE_FMT_S16", AV_SAMPLE_FMT_S16,
"", -1);
1008 audio_converted->nb_samples = audio_frame->nb_samples;
1009 av_samples_alloc(audio_converted->data, audio_converted->linesize,
info.
channels, audio_frame->nb_samples, AV_SAMPLE_FMT_S16, 0);
1011 AVAudioResampleContext *avr = NULL;
1016 avr = avresample_alloc_context();
1017 av_opt_set_int(avr,
"in_channel_layout", aCodecCtx->channel_layout, 0);
1018 av_opt_set_int(avr,
"out_channel_layout", aCodecCtx->channel_layout, 0);
1019 av_opt_set_int(avr,
"in_sample_fmt", aCodecCtx->sample_fmt, 0);
1020 av_opt_set_int(avr,
"out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
1025 int r = avresample_open(avr);
1028 nb_samples = avresample_convert(avr,
1029 audio_converted->data,
1030 audio_converted->linesize[0],
1031 audio_converted->nb_samples,
1033 audio_frame->linesize[0],
1034 audio_frame->nb_samples);
1038 memcpy(audio_buf, audio_converted->data[0], audio_converted->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) *
info.
channels);
1041 avresample_close(avr);
1042 avresample_free(&avr);
1047 av_free(audio_converted->data[0]);
1050 int starting_frame_number = -1;
1051 bool partial_frame =
true;
1052 for (
int channel_filter = 0; channel_filter <
info.
channels; channel_filter++)
1055 starting_frame_number = target_frame;
1056 int channel_buffer_size = packet_samples /
info.
channels;
1057 float *channel_buffer =
new float[channel_buffer_size];
1060 for (
int z = 0; z < channel_buffer_size; z++)
1061 channel_buffer[z] = 0.0f;
1067 for (
int sample = 0; sample < packet_samples; sample++)
1070 if (channel_filter == channel)
1073 channel_buffer[position] = audio_buf[sample] * (1.0f / (1 << 15));
1089 int start = starting_sample;
1090 int remaining_samples = channel_buffer_size;
1091 float *iterate_channel_buffer = channel_buffer;
1092 while (remaining_samples > 0)
1098 int samples = samples_per_frame - start;
1099 if (samples > remaining_samples)
1100 samples = remaining_samples;
1103 tr1::shared_ptr<Frame> f = CreateFrame(starting_frame_number);
1106 if (samples_per_frame == start + samples)
1107 partial_frame =
false;
1109 partial_frame =
true;
1113 f->AddAudio(
true, channel_filter, start, iterate_channel_buffer, samples, 0.98f);
1116 AppendDebugMethod(
"FFmpegReader::ProcessAudioPacket (f->AddAudio)",
"frame", starting_frame_number,
"start", start,
"samples", samples,
"channel", channel_filter,
"partial_frame", partial_frame,
"samples_per_frame", samples_per_frame);
1119 working_cache.
Add(f->number, f);
1122 remaining_samples -= samples;
1125 if (remaining_samples > 0)
1126 iterate_channel_buffer += samples;
1129 starting_frame_number++;
1136 delete[] channel_buffer;
1137 channel_buffer = NULL;
1138 iterate_channel_buffer = NULL;
1149 for (
long int f = target_frame; f < starting_frame_number; f++) {
1153 processing_audio_frames.erase(processing_audio_frames.find(f));
1156 if (processing_audio_frames.count(f) == 0)
1158 processed_audio_frames[f] = f;
1161 if (target_frame == starting_frame_number) {
1163 processing_audio_frames.erase(processing_audio_frames.find(target_frame));
1168 RemoveAVPacket(my_packet);
1171 AppendDebugMethod(
"FFmpegReader::ProcessAudioPacket (After)",
"requested_frame", requested_frame,
"starting_frame", target_frame,
"end_frame", starting_frame_number - 1,
"", -1,
"", -1,
"", -1);
1178 #pragma omp taskwait
1184 void FFmpegReader::Seek(
long int requested_frame)
throw(
TooManySeeks)
1187 if (requested_frame < 1)
1188 requested_frame = 1;
1189 if (requested_frame > info.video_length)
1190 requested_frame = info.video_length;
1193 AppendDebugMethod(
"FFmpegReader::Seek",
"requested_frame", requested_frame,
"seek_count", seek_count,
"last_frame", last_frame,
"", -1,
"", -1,
"", -1);
1196 working_cache.Clear();
1200 const GenericScopedLock<CriticalSection> lock(processingCriticalSection);
1201 processing_audio_frames.clear();
1202 processing_video_frames.clear();
1203 processed_video_frames.clear();
1204 processed_audio_frames.clear();
1205 duplicate_video_frames.clear();
1206 missing_video_frames.clear();
1211 current_video_frame = 0;
1212 largest_frame_processed = 0;
1213 num_checks_since_final = 0;
1214 num_packets_since_video_frame = 0;
1215 has_missing_frames =
false;
1221 int buffer_amount = 6;
1222 if (requested_frame - buffer_amount < 20)
1230 if (seek_count == 1) {
1233 seeking_pts = ConvertFrameToVideoPTS(1);
1235 seek_audio_frame_found = 0;
1236 seek_video_frame_found = 0;
1241 bool seek_worked =
false;
1242 int64_t seek_target = 0;
1245 if (!seek_worked && info.has_video)
1247 seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount);
1248 if (av_seek_frame(pFormatCtx, info.video_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
1249 fprintf(stderr,
"%s: error while seeking video stream\n", pFormatCtx->filename);
1253 is_video_seek =
true;
1259 if (!seek_worked && info.has_audio)
1261 seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount);
1262 if (info.has_audio && av_seek_frame(pFormatCtx, info.audio_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
1263 fprintf(stderr,
"%s: error while seeking audio stream\n", pFormatCtx->filename);
1267 is_video_seek =
false;
1277 avcodec_flush_buffers(aCodecCtx);
1281 avcodec_flush_buffers(pCodecCtx);
1284 previous_packet_location.frame = -1;
1285 previous_packet_location.sample_start = 0;
1289 if (seek_count == 1) {
1291 seeking_pts = seek_target;
1292 seeking_frame = requested_frame;
1294 seek_audio_frame_found = 0;
1295 seek_video_frame_found = 0;
1307 enable_seek =
false;
1317 long int FFmpegReader::GetVideoPTS()
1319 int current_pts = 0;
1320 if(packet->dts != AV_NOPTS_VALUE)
1321 current_pts = packet->dts;
1328 void FFmpegReader::UpdatePTSOffset(
bool is_video)
1334 if (video_pts_offset == 99999)
1336 video_pts_offset = 0 - GetVideoPTS();
1341 if (audio_pts_offset == 99999)
1343 audio_pts_offset = 0 - packet->pts;
1348 long int FFmpegReader::ConvertVideoPTStoFrame(
long int pts)
1351 pts = pts + video_pts_offset;
1352 long int previous_video_frame = current_video_frame;
1361 if (current_video_frame == 0)
1362 current_video_frame = frame;
1366 if (frame == previous_video_frame) {
1367 duplicate_video_frames.insert(pair<int,int>(frame, frame));
1374 current_video_frame++;
1376 if (current_video_frame < frame)
1378 AppendDebugMethod(
"FFmpegReader::ConvertVideoPTStoFrame (detected missing frame)",
"calculated frame", frame,
"previous_video_frame", previous_video_frame,
"current_video_frame", current_video_frame,
"", -1,
"", -1,
"", -1);
1382 while (current_video_frame < frame) {
1383 if (!missing_video_frames.count(current_video_frame))
1384 missing_video_frames.insert(pair<int, int>(previous_video_frame, current_video_frame));
1387 has_missing_frames =
true;
1390 current_video_frame++;
1399 long int FFmpegReader::ConvertFrameToVideoPTS(
long int frame_number)
1408 return video_pts - video_pts_offset;
1412 long int FFmpegReader::ConvertFrameToAudioPTS(
long int frame_number)
1421 return audio_pts - audio_pts_offset;
1425 AudioLocation FFmpegReader::GetAudioPTSLocation(
long int pts)
1428 pts = pts + audio_pts_offset;
1437 int whole_frame = int(frame);
1440 double sample_start_percentage = frame - double(whole_frame);
1446 int sample_start = round(
double(samples_per_frame) * sample_start_percentage);
1449 if (whole_frame < 1)
1451 if (sample_start < 0)
1458 if (previous_packet_location.
frame != -1 && location.
is_near(previous_packet_location, samples_per_frame, samples_per_frame))
1460 int orig_frame = location.
frame;
1464 if (previous_packet_location.
sample_start <= samples_per_frame)
1467 location.
frame = previous_packet_location.
frame;
1477 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,
"", -1);
1482 previous_packet_location = location;
1489 tr1::shared_ptr<Frame> FFmpegReader::CreateFrame(
long int requested_frame)
1492 tr1::shared_ptr<Frame> output = working_cache.
GetFrame(requested_frame);
1501 working_cache.
Add(requested_frame, output);
1504 if (requested_frame > largest_frame_processed)
1505 largest_frame_processed = requested_frame;
1513 bool FFmpegReader::IsPartialFrame(
long int requested_frame) {
1516 bool seek_trash =
false;
1517 long int max_seeked_frame = seek_audio_frame_found;
1518 if (seek_video_frame_found > max_seeked_frame)
1519 max_seeked_frame = seek_video_frame_found;
1520 if ((
info.
has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) ||
1521 (
info.
has_video && seek_video_frame_found && max_seeked_frame >= requested_frame))
1528 bool FFmpegReader::CheckMissingFrame(
long int requested_frame)
1531 AppendDebugMethod(
"FFmpegReader::CheckMissingFrame",
"requested_frame", requested_frame,
"has_missing_frames", has_missing_frames,
"missing_video_frames.size()", missing_video_frames.size(),
"", -1,
"", -1,
"", -1);
1534 if (
info.
has_video && !is_seeking && num_packets_since_video_frame > 60)
1536 deque<long int>::iterator oldest_video_frame;
1539 for(oldest_video_frame = frame_numbers.begin(); oldest_video_frame != frame_numbers.end(); ++oldest_video_frame)
1541 tr1::shared_ptr<Frame> f(working_cache.
GetFrame(*oldest_video_frame));
1544 if ((f == NULL) || (f != NULL && !f->has_image_data))
1545 if (!missing_video_frames.count(*oldest_video_frame))
1546 missing_video_frames.insert(pair<int, int>(current_video_frame, *oldest_video_frame));
1549 has_missing_frames =
true;
1552 current_video_frame = *oldest_video_frame;
1557 map<long int, long int>::iterator itr;
1558 bool found_missing_frame =
false;
1559 for(itr = missing_video_frames.begin(); itr != missing_video_frames.end(); ++itr)
1562 tr1::shared_ptr<Frame> missing_frame = CreateFrame(itr->second);
1563 if (last_video_frame != NULL && missing_frame != NULL) {
1564 missing_frame->AddImage(tr1::shared_ptr<QImage>(
new QImage(*last_video_frame->GetImage())),
true);
1569 processed_video_frames[itr->second] = itr->second;
1573 missing_video_frames.erase(itr);
1576 found_missing_frame =
true;
1580 return found_missing_frame;
1584 void FFmpegReader::CheckWorkingFrames(
bool end_of_stream,
long int requested_frame)
1598 num_checks_since_final++;
1600 bool is_video_ready =
false;
1601 bool is_audio_ready =
false;
1604 is_video_ready = processed_video_frames.count(f->number);
1605 is_audio_ready = processed_audio_frames.count(f->number);
1608 if (previous_packet_location.
frame == f->number && !end_of_stream)
1609 is_audio_ready =
false;
1610 bool is_seek_trash = IsPartialFrame(f->number);
1617 if (num_checks_since_final > 90 && (!is_video_ready || !is_audio_ready)) {
1618 if (
info.
has_video && !is_video_ready && last_video_frame != NULL) {
1621 f->AddImage(tr1::shared_ptr<QImage>(
new QImage(*last_video_frame->GetImage())),
true);
1622 processed_video_frames[f->number] = f->number;
1628 processed_audio_frames[f->number] = f->number;
1629 f->has_audio_data =
true;
1637 AppendDebugMethod(
"FFmpegReader::CheckWorkingFrames",
"frame_number", f->number,
"is_video_ready", is_video_ready,
"is_audio_ready", is_audio_ready,
"", -1,
"", -1,
"", -1);
1640 if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || is_seek_trash)
1643 AppendDebugMethod(
"FFmpegReader::CheckWorkingFrames (mark frame as final)",
"f->number", f->number,
"is_seek_trash", is_seek_trash,
"Working Cache Count", working_cache.
Count(),
"Final Cache Count",
final_cache.
Count(),
"", -1,
"", -1);
1648 num_checks_since_final = 0;
1654 working_cache.
Remove(f->number);
1657 last_frame = f->number;
1661 working_cache.
Remove(f->number);
1671 void FFmpegReader::CheckFPS()
1676 int first_second_counter = 0;
1677 int second_second_counter = 0;
1678 int third_second_counter = 0;
1679 int forth_second_counter = 0;
1680 int fifth_second_counter = 0;
1683 int threshold = 500;
1689 if (GetNextPacket() < 0)
1694 if (packet->stream_index == videoStream)
1700 UpdatePTSOffset(
true);
1703 long int pts = GetVideoPTS();
1706 RemoveAVFrame(pFrame);
1709 RemoveAVPacket(packet);
1712 pts += video_pts_offset;
1718 if (video_seconds <= 1.0)
1719 first_second_counter++;
1720 else if (video_seconds > 1.0 && video_seconds <= 2.0)
1721 second_second_counter++;
1722 else if (video_seconds > 2.0 && video_seconds <= 3.0)
1723 third_second_counter++;
1724 else if (video_seconds > 3.0 && video_seconds <= 4.0)
1725 forth_second_counter++;
1726 else if (video_seconds > 4.0 && video_seconds <= 5.0)
1727 fifth_second_counter++;
1734 RemoveAVPacket(packet);
1738 RemoveAVPacket(packet);
1744 if (iterations > threshold)
1749 if (second_second_counter == 0 || third_second_counter == 0 || forth_second_counter == 0 || fifth_second_counter == 0)
1758 int sum_fps = second_second_counter + third_second_counter + forth_second_counter + fifth_second_counter;
1759 int avg_fps = round(sum_fps / 4.0f);
1767 double diff = fps - double(avg_fps);
1770 if (diff <= -1 || diff >= 1)
1774 diff = half_fps - double(avg_fps);
1777 if (diff <= -1 || diff >= 1)
1794 void FFmpegReader::RemoveAVFrame(AVPicture* remove_frame)
1796 #pragma omp critical (packet_cache)
1799 if (frames.count(remove_frame))
1802 avpicture_free(frames[remove_frame]);
1805 frames.erase(remove_frame);
1808 delete remove_frame;
1815 void FFmpegReader::RemoveAVPacket(AVPacket* remove_packet)
1817 #pragma omp critical (packet_cache)
1820 if (packets.count(remove_packet))
1823 av_free_packet(remove_packet);
1826 packets.erase(remove_packet);
1829 delete remove_packet;
1836 long int FFmpegReader::GetSmallestVideoFrame()
1839 map<long int, long int>::iterator itr;
1840 int smallest_frame = -1;
1841 for(itr = processing_video_frames.begin(); itr != processing_video_frames.end(); ++itr)
1843 if (itr->first < smallest_frame || smallest_frame == -1)
1844 smallest_frame = itr->first;
1848 return smallest_frame;
1852 long int FFmpegReader::GetSmallestAudioFrame()
1855 map<long int, long int>::iterator itr;
1856 int smallest_frame = -1;
1858 for(itr = processing_audio_frames.begin(); itr != processing_audio_frames.end(); ++itr)
1860 if (itr->first < smallest_frame || smallest_frame == -1)
1861 smallest_frame = itr->first;
1865 return smallest_frame;
1880 root[
"type"] =
"FFmpegReader";
1881 root[
"path"] = path;
1892 Json::Reader reader;
1893 bool success = reader.parse( value, root );
1896 throw InvalidJSON(
"JSON could not be parsed (or is invalid)",
"");
1906 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)",
"");
1917 if (!root[
"path"].isNull())
1918 path = root[
"path"].asString();
#define AV_RESET_FRAME(av_frame)
long long file_size
Size of file (in bytes)
tr1::shared_ptr< Frame > GetFrame(long int requested_frame)
#define AV_FREE_FRAME(av_frame)
int num
Numerator for the fraction.
void Add(long int frame_number, tr1::shared_ptr< Frame > frame)
Add a Frame to the cache.
CriticalSection processingCriticalSection
ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
int width
The width of the video (in pixesl)
void Remove(long int frame_number)
Remove a specific frame.
This class represents a single frame of video (i.e. image & audio data)
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
float duration
Length of time (in seconds)
string acodec
The name of the audio codec used to encode / decode the video stream.
#define AVCODEC_MAX_AUDIO_FRAME_SIZE
#define OPEN_MP_NUM_PROCESSORS
deque< long int > GetFrameNumbers()
Return a deque of all frame numbers in this queue (returns just a copy of the data) ...
string Json()
Get and Set JSON methods.
Json::Value JsonValue()
Generate Json::JsonValue for this object.
Exception when a reader is closed, and a frame is requested.
bool has_video
Determines if this file has a video stream.
Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3) ...
FFmpegReader(string path)
void SetMaxBytesFromInfo(long int number_of_frames, int width, int height, int sample_rate, int channels)
Set maximum bytes to a different amount based on a ReaderInfo struct.
int audio_bit_rate
The bit rate of the audio stream (in bytes)
bool has_audio
Determines if this file has an audio stream.
void AppendDebugMethod(string method_name, string arg1_name, float arg1_value, string arg2_name, float arg2_value, string arg3_name, float arg3_value, string arg4_name, float arg4_value, string arg5_name, float arg5_value, string arg6_name, float arg6_value)
Append debug information as JSON.
Exception when no valid codec is found for a file.
int audio_stream_index
The index of the audio stream.
Exception when no streams are found in the file.
int height
The height of the video (in pixels)
void SetJson(string value)
Load JSON string into this object.
#define AV_ALLOCATE_FRAME()
Exception for files that can not be found or opened.
This class represents a fraction.
Cache final_cache
Final cache object used to hold final frames.
ChannelLayout
This enumeration determines the audio channel layout (such as stereo, mono, 5 point surround...
tr1::shared_ptr< Frame > GetSmallestFrame()
Get the smallest frame number.
virtual Json::Value JsonValue()=0
Generate Json::JsonValue for this object.
virtual void SetJsonValue(Json::Value root)=0
Load Json::JsonValue into this object.
ReaderInfo info
Information about the current media file.
Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Exception for frames that are out of bounds.
int is_near(AudioLocation location, int samples_per_frame, int amount)
Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square) ...
tr1::shared_ptr< Frame > GetFrame(long int frame_number)
Get a frame from the cache.
void Clear()
Clear the cache of all frames.
Exception for invalid JSON.
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
This struct holds the associated video frame and starting sample # for an audio packet.
void Open()
Open File - which is called by the constructor automatically.
int video_bit_rate
The bit rate of the video stream (in bytes)
Fraction audio_timebase
The audio timebase determines how long each audio packet should be played.
string vcodec
The name of the video codec used to encode / decode the video stream.
~FFmpegReader()
Destructor.
int den
Denominator for the fraction.
int channels
The number of audio channels used in the audio stream.
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
int video_stream_index
The index of the video stream.
long int video_length
The number of frames in the video stream.
int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
long int Count()
Count the frames in the queue.
double ToDouble()
Return this fraction as a double (i.e. 1/2 = 0.5)
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Exception when too many seek attempts happen.