Skip to content

Commit 728e002

Browse files
authored
MP3 Special Handling & Missing Frame Refactor (#196)
* Handle MP3 files with special logic, since they typically only have 1 frame of video * Better support for missing frames (handling of missing audio and missing video data separated), and fixed a missing audio regression.
1 parent 62fa717 commit 728e002

File tree

1 file changed

+38
-23
lines changed

1 file changed

+38
-23
lines changed

src/FFmpegReader.cpp

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,6 @@ std::shared_ptr<Frame> FFmpegReader::GetFrame(int64_t requested_frame)
472472
#pragma omp critical (ReadStream)
473473
{
474474
// Check the cache a 2nd time (due to a potential previous lock)
475-
if (has_missing_frames)
476-
CheckMissingFrame(requested_frame);
477475
frame = final_cache.GetFrame(requested_frame);
478476
if (frame) {
479477
// Debug output
@@ -648,9 +646,6 @@ std::shared_ptr<Frame> FFmpegReader::ReadStream(int64_t requested_frame)
648646

649647
// Check if working frames are 'finished'
650648
if (!is_seeking) {
651-
// Check for any missing frames
652-
CheckMissingFrame(requested_frame);
653-
654649
// Check for final frames
655650
CheckWorkingFrames(false, requested_frame);
656651
}
@@ -1651,7 +1646,7 @@ AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts)
16511646
for (int64_t audio_frame = previous_packet_location.frame; audio_frame < location.frame; audio_frame++) {
16521647
if (!missing_audio_frames.count(audio_frame)) {
16531648
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAudioPTSLocation (tracking missing frame)", "missing_audio_frame", audio_frame, "previous_audio_frame", previous_packet_location.frame, "new location frame", location.frame, "", -1, "", -1, "", -1);
1654-
missing_audio_frames.insert(pair<int64_t, int64_t>(previous_packet_location.frame - 1, audio_frame));
1649+
missing_audio_frames.insert(pair<int64_t, int64_t>(audio_frame, previous_packet_location.frame - 1));
16551650
}
16561651
}
16571652
}
@@ -1726,13 +1721,25 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame)
17261721
map<int64_t, int64_t>::iterator itr;
17271722
bool found_missing_frame = false;
17281723

1729-
// Check if requested frame is a missing frame
1730-
if (missing_video_frames.count(requested_frame) || missing_audio_frames.count(requested_frame)) {
1731-
int64_t missing_source_frame = -1;
1732-
if (missing_video_frames.count(requested_frame))
1733-
missing_source_frame = missing_video_frames.find(requested_frame)->second;
1734-
else if (missing_audio_frames.count(requested_frame))
1735-
missing_source_frame = missing_audio_frames.find(requested_frame)->second;
1724+
// Special MP3 Handling (ignore more than 1 video frame)
1725+
if (info.has_audio and info.has_video) {
1726+
AVCodecID aCodecId = AV_FIND_DECODER_CODEC_ID(aStream);
1727+
AVCodecID vCodecId = AV_FIND_DECODER_CODEC_ID(pStream);
1728+
// If MP3 with single video frame, handle this special case by copying the previously
1729+
// decoded image to the new frame. Otherwise, it will spend a huge amount of
1730+
// CPU time looking for missing images for all the audio-only frames.
1731+
if (checked_count > 8 && !missing_video_frames.count(requested_frame) &&
1732+
!processing_audio_frames.count(requested_frame) && processed_audio_frames.count(requested_frame) &&
1733+
last_frame && last_video_frame->has_image_data && aCodecId == AV_CODEC_ID_MP3 && (vCodecId == AV_CODEC_ID_MJPEGB || vCodecId == AV_CODEC_ID_MJPEG)) {
1734+
missing_video_frames.insert(pair<int64_t, int64_t>(requested_frame, last_video_frame->number));
1735+
missing_video_frames_source.insert(pair<int64_t, int64_t>(last_video_frame->number, requested_frame));
1736+
missing_frames.Add(last_video_frame);
1737+
}
1738+
}
1739+
1740+
// Check if requested video frame is a missing
1741+
if (missing_video_frames.count(requested_frame)) {
1742+
int64_t missing_source_frame = missing_video_frames.find(requested_frame)->second;
17361743

17371744
// Increment missing source frame check count (or init to 1)
17381745
if (checked_frames.count(missing_source_frame) == 0)
@@ -1765,21 +1772,26 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame)
17651772
std::shared_ptr<QImage> parent_image = parent_frame->GetImage();
17661773
if (parent_image) {
17671774
missing_frame->AddImage(std::shared_ptr<QImage>(new QImage(*parent_image)));
1768-
17691775
processed_video_frames[missing_frame->number] = missing_frame->number;
1770-
processed_audio_frames[missing_frame->number] = missing_frame->number;
1776+
}
1777+
}
1778+
}
17711779

1772-
// Move frame to final cache
1773-
final_cache.Add(missing_frame);
1780+
// Check if requested audio frame is a missing
1781+
if (missing_audio_frames.count(requested_frame)) {
17741782

1775-
// Remove frame from working cache
1776-
working_cache.Remove(missing_frame->number);
1783+
// Create blank missing frame
1784+
std::shared_ptr<Frame> missing_frame = CreateFrame(requested_frame);
17771785

1778-
// Update last_frame processed
1779-
last_frame = missing_frame->number;
1780-
}
1781-
}
1786+
// Get Samples per frame (for this frame number)
1787+
int samples_per_frame = Frame::GetSamplesPerFrame(missing_frame->number, info.fps, info.sample_rate, info.channels);
1788+
1789+
// Debug output
1790+
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckMissingFrame (Add Silence for Missing Audio Frame)", "requested_frame", requested_frame, "missing_frame->number", missing_frame->number, "samples_per_frame", samples_per_frame, "", -1, "", -1, "", -1);
17821791

1792+
// Add this frame to the processed map (since it's already done)
1793+
missing_frame->AddAudioSilence(samples_per_frame);
1794+
processed_audio_frames[missing_frame->number] = missing_frame->number;
17831795
}
17841796

17851797
return found_missing_frame;
@@ -1792,6 +1804,9 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram
17921804
bool checked_count_tripped = false;
17931805
int max_checked_count = 80;
17941806

1807+
// Check if requested frame is 'missing'
1808+
CheckMissingFrame(requested_frame);
1809+
17951810
while (true)
17961811
{
17971812
// Get the front frame of working cache

0 commit comments

Comments
 (0)