void FFMS_Indexer::WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track) { // Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers. if (!DecodeFrame->nb_samples) return; if (!AudioContext.W64Writer) { FFMS_AudioProperties AP; FillAP(AP, AudioContext.CodecContext, (*Index)[Track]); int FNSize = (*ANC)(SourceFile.c_str(), Track, &AP, NULL, 0, ANCPrivate); if (FNSize <= 0) { DumpMask = DumpMask & ~(1 << Track); return; } int Format = av_get_packed_sample_fmt(AudioContext.CodecContext->sample_fmt); std::vector<char> WName(FNSize + 1); (*ANC)(SourceFile.c_str(), Track, &AP, &WName[0], FNSize, ANCPrivate); WName.back() = 0; try { AudioContext.W64Writer = new Wave64Writer(WName.data(), av_get_bytes_per_sample(AudioContext.CodecContext->sample_fmt), AudioContext.CodecContext->channels, AudioContext.CodecContext->sample_rate, (Format == AV_SAMPLE_FMT_FLT) || (Format == AV_SAMPLE_FMT_DBL)); } catch (...) { throw FFMS_Exception(FFMS_ERROR_WAVE_WRITER, FFMS_ERROR_FILE_WRITE, "Failed to write wave data"); } } AudioContext.W64Writer->WriteData(*DecodeFrame); }
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; }