FFMS_AudioSource::FFMS_AudioSource(const char *SourceFile, FFMS_Index &Index, int Track) : Delay(0) , MaxCacheBlocks(50) , BytesPerSample(0) , NeedsResample(false) , CurrentSample(-1) , PacketNumber(0) , CurrentFrame(NULL) , TrackNumber(Track) , SeekOffset(0) , Index(Index) { if (Track < 0 || Track >= static_cast<int>(Index.size())) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Out of bounds track index selected"); if (Index[Track].TT != FFMS_TYPE_AUDIO) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Not an audio track"); if (Index[Track].empty()) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Audio track contains no audio frames"); if (!Index.CompareFileSignature(SourceFile)) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH, "The index does not match the source file"); Frames = Index[Track]; Index.AddRef(); }
void FFMS_AudioSource::Init(const FFMS_Index &Index, int DelayMode) { // Decode the first packet to ensure all properties are initialized // Don't cache it since it might be in the wrong format // Instead, leave it in DecodeFrame and it'll get cached later while (DecodeFrame->nb_samples == 0) DecodeNextBlock(); // Read properties of the audio which may not be available until the first // frame has been decoded FillAP(AP, CodecContext, Frames); if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Codec returned zero size audio"); std::auto_ptr<FFMS_ResampleOptions> opt(CreateResampleOptions()); SetOutputFormat(opt.get()); if (DelayMode < FFMS_DELAY_NO_SHIFT) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Bad audio delay compensation mode"); if (DelayMode == FFMS_DELAY_NO_SHIFT) return; if (DelayMode > (signed)Index.size()) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Out of bounds track index selected for audio delay compensation"); if (DelayMode >= 0 && Index[DelayMode].TT != FFMS_TYPE_VIDEO) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Audio delay compensation must be relative to a video track"); int64_t Delay = 0; if (DelayMode != FFMS_DELAY_TIME_ZERO) { if (DelayMode == FFMS_DELAY_FIRST_VIDEO_TRACK) { for (size_t i = 0; i < Index.size(); ++i) { if (Index[i].TT == FFMS_TYPE_VIDEO && !Index[i].empty()) { DelayMode = i; break; } } } if (DelayMode >= 0) { const FFMS_Track &VTrack = Index[DelayMode]; Delay = -(VTrack[0].PTS * VTrack.TB.Num * AP.SampleRate / (VTrack.TB.Den * 1000)); } } if (Frames.HasTS) { int i = 0; while (Frames[i].PTS == ffms_av_nopts_value) ++i; Delay += Frames[i].PTS * Frames.TB.Num * AP.SampleRate / (Frames.TB.Den * 1000); for (; i >= 0; --i) Delay -= Frames[i].SampleCount; } AP.NumSamples += Delay; }
FFMS_VideoSource::FFMS_VideoSource(const char *SourceFile, FFMS_Index &Index, int Track, int Threads) : Index(Index) , CodecContext(NULL) { if (Track < 0 || Track >= static_cast<int>(Index.size())) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Out of bounds track index selected"); if (Index[Track].TT != FFMS_TYPE_VIDEO) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Not a video track"); if (Index[Track].empty()) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Video track contains no frames"); if (!Index.CompareFileSignature(SourceFile)) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH, "The index does not match the source file"); Frames = Index[Track]; VideoTrack = Track; memset(&VP, 0, sizeof(VP)); SWS = NULL; LastFrameNum = 0; CurrentFrame = 1; DelayCounter = 0; InitialDecode = 1; LastFrameHeight = -1; LastFrameWidth = -1; LastFramePixelFormat = PIX_FMT_NONE; TargetHeight = -1; TargetWidth = -1; TargetResizer = 0; OutputFormat = PIX_FMT_NONE; OutputColorSpace = AVCOL_SPC_UNSPECIFIED; OutputColorRange = AVCOL_RANGE_UNSPECIFIED; InputFormatOverridden = false; InputFormat = PIX_FMT_NONE; InputColorSpace = AVCOL_SPC_UNSPECIFIED; InputColorRange = AVCOL_RANGE_UNSPECIFIED; if (Threads < 1) DecodingThreads = GetNumberOfLogicalCPUs(); else DecodingThreads = Threads; DecodeFrame = avcodec_alloc_frame(); LastDecodedFrame = avcodec_alloc_frame(); // Dummy allocations so the unallocated case doesn't have to be handled later avpicture_alloc(&SWSFrame, PIX_FMT_GRAY8, 16, 16); Index.AddRef(); }
FFMS_API(FFMS_Index *) FFMS_ReadIndex(const char *IndexFile, FFMS_ErrorInfo *ErrorInfo) { ClearErrorInfo(ErrorInfo); FFMS_Index *Index = new FFMS_Index(); try { Index->ReadIndex(IndexFile); } catch (FFMS_Exception &e) { delete Index; e.CopyOut(ErrorInfo); return NULL; } return Index; }
FFMS_AudioSource::FFMS_AudioSource(const char *SourceFile, FFMS_Index &Index, int Track) : TrackNumber(Track) { if (Track < 0 || Track >= static_cast<int>(Index.size())) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Out of bounds track index selected"); if (Index[Track].TT != FFMS_TYPE_AUDIO) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Not an audio track"); if (Index[Track].empty()) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Audio track contains no audio frames"); if (!Index.CompareFileSignature(SourceFile)) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH, "The index does not match the source file"); Frames = Index[Track]; }
FFMS_VideoSource::FFMS_VideoSource(const char *SourceFile, FFMS_Index &Index, int Track, int Threads) : Index(Index) , CodecContext(nullptr) { if (Track < 0 || Track >= static_cast<int>(Index.size())) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Out of bounds track index selected"); if (Index[Track].TT != FFMS_TYPE_VIDEO) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Not a video track"); if (Index[Track].empty()) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT, "Video track contains no frames"); if (!Index.CompareFileSignature(SourceFile)) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH, "The index does not match the source file"); Frames = Index[Track]; VideoTrack = Track; VP = {}; LocalFrame = {}; SWS = nullptr; LastFrameNum = 0; CurrentFrame = 1; DelayCounter = 0; InitialDecode = 1; LastFrameHeight = -1; LastFrameWidth = -1; LastFramePixelFormat = FFMS_PIX_FMT(NONE); TargetHeight = -1; TargetWidth = -1; TargetResizer = 0; OutputFormat = FFMS_PIX_FMT(NONE); OutputColorSpace = AVCOL_SPC_UNSPECIFIED; OutputColorRange = AVCOL_RANGE_UNSPECIFIED; InputFormatOverridden = false; InputFormat = FFMS_PIX_FMT(NONE); InputColorSpace = AVCOL_SPC_UNSPECIFIED; InputColorRange = AVCOL_RANGE_UNSPECIFIED; if (Threads < 1) // libav current has issues with greater than 16 threads DecodingThreads = (std::min)(std::thread::hardware_concurrency(), 16u); else DecodingThreads = Threads; DecodeFrame = av_frame_alloc(); LastDecodedFrame = av_frame_alloc(); // Dummy allocations so the unallocated case doesn't have to be handled later if (av_image_alloc(SWSFrameData, SWSFrameLinesize, 16, 16, FFMS_PIX_FMT(GRAY8), 4) < 0) throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_ALLOCATION_FAILED, "Could not allocate dummy frame."); Index.AddRef(); }