void FFMS_AudioSource::CacheBeginning() { // Nothing to do if the cache is already populated if (!Cache.empty()) return; // The first frame is already decoded, so add it to the cache CacheIterator it = Cache.end(); CacheBlock(it); // The first packet after a seek is often decoded incorrectly, which // makes it impossible to ever correctly seek back to the beginning, so // store the first block now // In addition, anything with the same PTS as the first packet can't be // distinguished from the first packet and so can't be seeked to, so // store those as well // Some of LAVF's splitters don't like to seek to the beginning of the // file (ts and?), so cache a few blocks even if PTSes are unique // Packet 7 is the last packet I've had be unseekable to, so cache up to // 10 for a bit of an extra buffer CacheIterator end = Cache.end(); while (PacketNumber < Frames.size() && ((Frames[0].PTS != ffms_av_nopts_value && Frames[PacketNumber].PTS == Frames[0].PTS) || Cache.size() < 10)) { // Vorbis in particular seems to like having 60+ packets at the start // of the file with a PTS of 0, so we might need to expand the search // range to account for that. // Expanding slightly before it's strictly needed to ensure there's a // bit of space for an actual cache if (Cache.size() >= MaxCacheBlocks - 5) { if (MaxCacheBlocks >= EXCESSIVE_CACHE_SIZE) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_ALLOCATION_FAILED, "Exceeded the search range for an initial valid audio PTS"); MaxCacheBlocks *= 2; } DecodeNextBlock(&end); } // Store the iterator to the last element of the cache which is used for // correctness rather than speed, so that when looking for one to delete // we know how much to skip CacheNoDelete = Cache.end(); --CacheNoDelete; }
void FFMS_AudioSource::DecodeNextBlock(CacheIterator *pos) { CurrentFrame = &Frames[PacketNumber]; AVPacket Packet; if (!ReadPacket(&Packet)) throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_UNKNOWN, "ReadPacket unexpectedly failed to read a packet"); // ReadPacket may have changed the packet number CurrentFrame = &Frames[PacketNumber]; CurrentSample = CurrentFrame->SampleStart; bool GotSamples = false; uint8_t *Data = Packet.data; while (Packet.size > 0) { DecodeFrame.reset(); int GotFrame = 0; int Ret = avcodec_decode_audio4(CodecContext, DecodeFrame, &GotFrame, &Packet); // Should only ever happen if the user chose to ignore decoding errors // during indexing, so continue to just ignore decoding errors if (Ret < 0) break; if (Ret > 0) { Packet.size -= Ret; Packet.data += Ret; if (GotFrame && DecodeFrame->nb_samples > 0) { GotSamples = true; if (pos) CacheBlock(*pos); } } } Packet.data = Data; FreePacket(&Packet); // Zero sample packets aren't included in the index if (GotSamples) ++PacketNumber; }