void FFMS_VideoSource::SetPP(const char *PP) {

#ifdef FFMS_USE_POSTPROC
	if (PPMode)
		pp_free_mode(PPMode);
	PPMode = NULL;

	if (PP != NULL && strcmp(PP, "")) {
		// due to a parsing bug in libpostproc it can read beyond the end of a string
		// adding a ',' prevents the bug from manifesting
		// libav head 2011-08-26
		std::string s = PP;
		s.append(",");
		PPMode = pp_get_mode_by_name_and_quality(s.c_str(), PP_QUALITY_MAX);
		if (!PPMode) {
			ResetPP();
			throw FFMS_Exception(FFMS_ERROR_POSTPROCESSING, FFMS_ERROR_INVALID_ARGUMENT,
				"Invalid postprocesing settings");
		}
		
	}

	ReAdjustPP(CodecContext->pix_fmt, CodecContext->width, CodecContext->height);
	OutputFrame(DecodeFrame);
#else
	throw FFMS_Exception(FFMS_ERROR_POSTPROCESSING, FFMS_ERROR_UNSUPPORTED,
		"FFMS2 was not compiled with postprocessing support");
#endif /* FFMS_USE_POSTPROC */
}
Exemple #2
0
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();
}
Exemple #3
0
FFLAVFAudio::FFLAVFAudio(const char *SourceFile, int Track, FFMS_Index &Index, int DelayMode)
    : FFMS_AudioSource(SourceFile, Index, Track)
    , FormatContext(NULL)
    , LastValidTS(AV_NOPTS_VALUE)
{
    LAVFOpenFile(SourceFile, FormatContext);

    CodecContext.reset(FormatContext->streams[TrackNumber]->codec);
    assert(CodecContext);

    AVCodec *Codec = avcodec_find_decoder(CodecContext->codec_id);
    try {
        if (!Codec)
            throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
                                 "Audio codec not found");

        if (avcodec_open2(CodecContext, Codec, NULL) < 0)
            throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
                                 "Could not open audio codec");
    }
    catch (...) {
        avformat_close_input(&FormatContext);
        throw;
    }

    if (Frames.back().PTS == Frames.front().PTS)
        SeekOffset = -1;
    else
        SeekOffset = 10;
    Init(Index, DelayMode);
}
Exemple #4
0
bool FFLAVFVideo::SeekTo(int n, int SeekOffset) {
	if (SeekMode >= 0) {
		int TargetFrame = n + SeekOffset;
		if (TargetFrame < 0)
			throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_UNKNOWN,
			"Frame accurate seeking is not possible in this file");

		if (SeekMode < 3)
			TargetFrame = Frames.FindClosestVideoKeyFrame(TargetFrame);

		if (SeekMode == 0) {
			if (n < CurrentFrame) {
				av_seek_frame(FormatContext, VideoTrack, Frames[0].PTS, AVSEEK_FLAG_BACKWARD);
				FlushBuffers(CodecContext);
				CurrentFrame = 0;
				DelayCounter = 0;
				InitialDecode = 1;
			}
		} else {
			// 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat
			if (n < CurrentFrame || TargetFrame > CurrentFrame + 10 || (SeekMode == 3 && n > CurrentFrame + 10)) {
				av_seek_frame(FormatContext, VideoTrack, Frames[TargetFrame].PTS, AVSEEK_FLAG_BACKWARD);
				FlushBuffers(CodecContext);
				DelayCounter = 0;
				InitialDecode = 1;
				return true;
			}
		}
	} else if (n < CurrentFrame) {
		throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_INVALID_ARGUMENT,
			"Non-linear access attempted");
	}
	return false;
}
Exemple #5
0
FFMS_API(FFMS_AudioSource *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFMS_Index *Index, int DelayMode, FFMS_ErrorInfo *ErrorInfo) {
	try {
		switch (Index->Decoder) {
			case FFMS_SOURCE_LAVF:
				return new FFLAVFAudio(SourceFile, Track, *Index, DelayMode);
			case FFMS_SOURCE_MATROSKA:
				return new FFMatroskaAudio(SourceFile, Track, *Index, DelayMode);
#ifdef HAALISOURCE
			case FFMS_SOURCE_HAALIMPEG:
				if (HasHaaliMPEG)
					return new FFHaaliAudio(SourceFile, Track, *Index, FFMS_SOURCE_HAALIMPEG, DelayMode);
				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali MPEG/TS source unavailable");
			case FFMS_SOURCE_HAALIOGG:
				if (HasHaaliOGG)
					return new FFHaaliAudio(SourceFile, Track, *Index, FFMS_SOURCE_HAALIOGG, DelayMode);
				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali OGG/OGM source unavailable");
#endif
			default:
				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Unsupported format");
		}
	} catch (FFMS_Exception &e) {
		e.CopyOut(ErrorInfo);
		return NULL;
	}
}
Exemple #6
0
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;
}
Exemple #7
0
FFMS_Indexer *CreateIndexer(const char *Filename, FFMS_Sources Demuxer) {
	AVFormatContext *FormatContext = NULL;

	if (avformat_open_input(&FormatContext, Filename, NULL, NULL) != 0)
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("Can't open '") + Filename + "'");

	// Demuxer was not forced, probe for the best one to use
	if (Demuxer == FFMS_SOURCE_DEFAULT) {
		// Do matroska indexing instead?
		if (!strncmp(FormatContext->iformat->name, "matroska", 8)) {
			avformat_close_input(&FormatContext);
			return CreateMatroskaIndexer(Filename);
		}

#ifdef HAALISOURCE
		// Do haali ts indexing instead?
		if (HasHaaliMPEG && (!strcmp(FormatContext->iformat->name, "mpeg") || !strcmp(FormatContext->iformat->name, "mpegts"))) {
			avformat_close_input(&FormatContext);
			return CreateHaaliIndexer(Filename, FFMS_SOURCE_HAALIMPEG);
		}

		if (HasHaaliOGG && !strcmp(FormatContext->iformat->name, "ogg")) {
			avformat_close_input(&FormatContext);
			return CreateHaaliIndexer(Filename, FFMS_SOURCE_HAALIOGG);
		}
#endif

		return CreateLavfIndexer(Filename, FormatContext);
	}

	// someone forced a demuxer, use it
	if (Demuxer != FFMS_SOURCE_LAVF)
		avformat_close_input(&FormatContext);
#if !defined(HAALISOURCE)
	if (Demuxer == FFMS_SOURCE_HAALIOGG || Demuxer == FFMS_SOURCE_HAALIMPEG) {
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Your binary was not compiled with support for Haali's DirectShow parsers");
	}
#endif // !defined(HAALISOURCE)

	switch (Demuxer) {
		case FFMS_SOURCE_LAVF:
			return CreateLavfIndexer(Filename, FormatContext);
#ifdef HAALISOURCE
		case FFMS_SOURCE_HAALIOGG:
			if (!HasHaaliOGG)
				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali's Ogg parser is not available");
			return CreateHaaliIndexer(Filename, FFMS_SOURCE_HAALIOGG);
		case FFMS_SOURCE_HAALIMPEG:
			if (!HasHaaliMPEG)
				throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali's MPEG PS/TS parser is not available");
			return CreateHaaliIndexer(Filename, FFMS_SOURCE_HAALIMPEG);
#endif
		case FFMS_SOURCE_MATROSKA:
			return CreateMatroskaIndexer(Filename);
		default:
			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_INVALID_ARGUMENT, "Invalid demuxer requested");
	}
}
Exemple #8
0
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();
}
Exemple #9
0
void LAVFOpenFile(const char *SourceFile, AVFormatContext *&FormatContext) {
	if (avformat_open_input(&FormatContext, SourceFile, NULL, NULL) != 0)
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("Couldn't open '") + SourceFile + "'");

	if (avformat_find_stream_info(FormatContext,NULL) < 0) {
		avformat_close_input(&FormatContext);
		FormatContext = NULL;
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			"Couldn't find stream information");
	}
}
Exemple #10
0
void FFMS_AudioSource::SetOutputFormat(FFMS_ResampleOptions const& opt) {
	if (opt.SampleRate != AP.SampleRate)
		throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
			"Sample rate changes are currently unsupported.");

#ifndef FFMS_RESAMPLING_ENABLED
	if (opt.SampleFormat != AP.SampleFormat || opt.SampleRate != AP.SampleRate || opt.ChannelLayout != AP.ChannelLayout)
		throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
			"FFMS was not built with resampling enabled. The only supported conversion is interleaving planar audio.");
#endif
#ifdef WITH_AVRESAMPLE
	if (opt.SampleFormat != AP.SampleFormat || opt.ChannelLayout != AP.ChannelLayout)
		throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
			"FFMS was not built with FFMPEG resampling enabled.");
#endif

	// Cache stores audio in the output format, so clear it and reopen the file
	Cache.clear();
	PacketNumber = 0;
	ReopenFile();
	FlushBuffers(CodecContext);

	BytesPerSample = av_get_bytes_per_sample(static_cast<AVSampleFormat>(opt.SampleFormat)) * av_get_channel_layout_nb_channels(opt.ChannelLayout);
	NeedsResample =
		opt.SampleFormat != (int)CodecContext->sample_fmt ||
		opt.SampleRate != AP.SampleRate ||
		opt.ChannelLayout != AP.ChannelLayout ||
		opt.ForceResample;

#ifdef FFMS_RESAMPLING_ENABLED
	if (!NeedsResample) return;

	FFResampleContext newContext;
	SetOptions(opt, newContext, resample_options);
	av_opt_set_int(newContext, "in_sample_rate", AP.SampleRate, 0);
	av_opt_set_int(newContext, "in_sample_fmt", CodecContext->sample_fmt, 0);
	av_opt_set_int(newContext, "in_channel_layout", AP.ChannelLayout, 0);

	av_opt_set_int(newContext, "out_sample_rate", opt.SampleRate, 0);

#ifdef WITH_SWRESAMPLE
	av_opt_set_channel_layout(newContext, "out_channel_layout", opt.ChannelLayout, 0);
	av_opt_set_sample_fmt(newContext, "out_sample_fmt", (AVSampleFormat)opt.SampleFormat, 0);
#endif

	if (ffms_open(newContext))
		throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNKNOWN,
			"Could not open avresample context");
	newContext.swap(ResampleContext);
#endif
}
void FFMS_VideoSource::ReAdjustOutputFormat() {
	if (SWS) {
		sws_freeContext(SWS);
		SWS = nullptr;
	}

	DetectInputFormat();

	OutputFormat = FindBestPixelFormat(TargetPixelFormats, InputFormat);
	if (OutputFormat == FFMS_PIX_FMT(NONE)) {
		ResetOutputFormat();
		throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
			"No suitable output format found");
	}

	OutputColorRange = handle_jpeg(&OutputFormat);
	if (OutputColorRange == AVCOL_RANGE_UNSPECIFIED)
		OutputColorRange = CodecContext->color_range;
	if (OutputColorRange == AVCOL_RANGE_UNSPECIFIED)
		OutputColorRange = InputColorRange;

	OutputColorSpace = CodecContext->colorspace;
	if (OutputColorSpace == AVCOL_SPC_UNSPECIFIED)
		OutputColorSpace = InputColorSpace;

	if (InputFormat != OutputFormat ||
		TargetWidth != CodecContext->width ||
		TargetHeight != CodecContext->height ||
		InputColorSpace != OutputColorSpace ||
		InputColorRange != OutputColorRange)
	{
		SWS = GetSwsContext(
			CodecContext->width, CodecContext->height, InputFormat, InputColorSpace, InputColorRange,
			TargetWidth, TargetHeight, OutputFormat, OutputColorSpace, OutputColorRange,
			TargetResizer);

		if (!SWS) {
			ResetOutputFormat();
			throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
				"Failed to allocate SWScale context");
		}
	}

	av_freep(&SWSFrameData[0]);
	if (av_image_alloc(SWSFrameData, SWSFrameLinesize, TargetWidth, TargetHeight, OutputFormat, 4) < 0)
		throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_ALLOCATION_FAILED,
			"Could not allocate frame with new resolution.");
}
Exemple #12
0
void LAVFOpenFile(const char *SourceFile, AVFormatContext *&FormatContext, int Track) {
	if (avformat_open_input(&FormatContext, SourceFile, nullptr, nullptr) != 0)
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("Couldn't open '") + SourceFile + "'");

	if (avformat_find_stream_info(FormatContext,nullptr) < 0) {
		avformat_close_input(&FormatContext);
		FormatContext = nullptr;
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			"Couldn't find stream information");
	}

	for (int i = 0; i < (int) FormatContext->nb_streams; i++)
		if (i != Track)
			FormatContext->streams[i]->discard = AVDISCARD_ALL;
}
Exemple #13
0
int64_t FileHandle::Size() {
	int64_t size = avio_size(avio);
	if (size < 0)
		throw FFMS_Exception(error_source, FFMS_ERROR_FILE_READ,
			"Failed to get file size for '" + filename +"'");
	return size;
}
Exemple #14
0
size_t FileHandle::Read(char *buffer, size_t size) {
	int count = avio_read(avio, (unsigned char *)buffer, size);
	if (count < 0)
		throw FFMS_Exception(error_source, FFMS_ERROR_FILE_READ,
			"Failed to read from '" + filename + "'");
	return (size_t)count;
}
Exemple #15
0
int64_t FileHandle::Tell() {
	int64_t ret = avio_tell(avio);
	if (ret < 0)
		throw FFMS_Exception(error_source, error_cause,
			"Failed to read position in '" + filename + "'");
	return ret;
}
Exemple #16
0
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);
}
Exemple #17
0
void FFMS_Indexer::SetErrorHandling(int ErrorHandling) {
	if (ErrorHandling != FFMS_IEH_ABORT && ErrorHandling != FFMS_IEH_CLEAR_TRACK &&
		ErrorHandling != FFMS_IEH_STOP_TRACK && ErrorHandling != FFMS_IEH_IGNORE)
		throw FFMS_Exception(FFMS_ERROR_INDEXING, FFMS_ERROR_INVALID_ARGUMENT,
			"Invalid error handling mode specified");
	this->ErrorHandling = ErrorHandling;
}
Exemple #18
0
size_t FileHandle::Write(const char *buffer, size_t size) {
	avio_write(avio, (const unsigned char *)buffer, size);
	avio_flush(avio);
	if (avio->error < 0)
		throw FFMS_Exception(error_source, FFMS_ERROR_FILE_WRITE,
			"Failed to write to '" + filename + "'");
	return size;
}
// this might look stupid, but we have actually had crashes caused by not checking like this.
static void SanityCheckFrameForData(AVFrame *Frame) {
	for (int i = 0; i < 4; i++) {
		if (Frame->data[i] != NULL && Frame->linesize[i] > 0)
			return;
	}

	throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Insanity detected: decoder returned an empty frame");
}
Exemple #20
0
void FFMS_VideoSource::ReAdjustOutputFormat() {
	if (SWS) {
		sws_freeContext(SWS);
		SWS = NULL;
	}

	DetectInputFormat();

	OutputFormat = FindBestPixelFormat(TargetPixelFormats, InputFormat);
	if (OutputFormat == PIX_FMT_NONE) {
		ResetOutputFormat();
		throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
			"No suitable output format found");
	}

	OutputColorRange = handle_jpeg(&OutputFormat);
	if (OutputColorRange == AVCOL_RANGE_UNSPECIFIED)
		OutputColorRange = CodecContext->color_range;
	if (OutputColorRange == AVCOL_RANGE_UNSPECIFIED)
		OutputColorRange = InputColorRange;

	OutputColorSpace = CodecContext->colorspace;
	if (OutputColorSpace == AVCOL_SPC_UNSPECIFIED)
		OutputColorSpace = InputColorSpace;

	if (InputFormat != OutputFormat ||
		TargetWidth != CodecContext->width ||
		TargetHeight != CodecContext->height ||
		InputColorSpace != OutputColorSpace ||
		InputColorRange != OutputColorRange)
	{
		SWS = GetSwsContext(
			CodecContext->width, CodecContext->height, InputFormat, InputColorSpace, InputColorRange,
			TargetWidth, TargetHeight, OutputFormat, OutputColorSpace, OutputColorRange,
			TargetResizer);

		if (!SWS) {
			ResetOutputFormat();
			throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
				"Failed to allocate SWScale context");
		}
	}

	avpicture_free(&SWSFrame);
	avpicture_alloc(&SWSFrame, OutputFormat, TargetWidth, TargetHeight);
}
Exemple #21
0
FFMS_Index::FFMS_Index(const char *IndexFile)
: RefCount(1)
{
	ZipFile zf(IndexFile, "rb");

	// Read the index file header
	if (zf.Read<uint32_t>() != INDEXID)
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("'") + IndexFile + "' is not a valid index file");

	if (zf.Read<uint32_t>() != FFMS_VERSION)
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("'") + IndexFile + "' is not the expected index version");

	uint32_t Tracks = zf.Read<uint32_t>();
	Decoder = zf.Read<uint32_t>();
	ErrorHandling = zf.Read<uint32_t>();

	if (!(Decoder & FFMS_GetEnabledSources()))
		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_NOT_AVAILABLE,
			"The source which this index was created with is not available");

	if (zf.Read<uint32_t>() != avutil_version() ||
		zf.Read<uint32_t>() != avformat_version() ||
		zf.Read<uint32_t>() != avcodec_version() ||
		zf.Read<uint32_t>() != swscale_version())
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("A different FFmpeg build was used to create '") + IndexFile + "'");

	Filesize = zf.Read<int64_t>();
	zf.Read(Digest, sizeof(Digest));

	reserve(Tracks);
	try {
		for (size_t i = 0; i < Tracks; ++i)
			push_back(FFMS_Track(zf));
	}
	catch (FFMS_Exception const&) {
		throw;
	}
	catch (...) {
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("Unknown error while reading index information in '") + IndexFile + "'");
	}
}
FFLAVFIndexer::FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext) : FFMS_Indexer(Filename) {
	this->FormatContext = FormatContext;

	if (avformat_find_stream_info(FormatContext,NULL) < 0) {
		avformat_close_input(&FormatContext);
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			"Couldn't find stream information");
	}
}
Exemple #23
0
FileHandle::FileHandle(const char *filename, const char *mode, int error_source, int error_cause)
: avio(ffms_fopen(filename, mode))
, filename(filename)
, error_source(error_source)
, error_cause(error_cause)
{
	if (!avio)
		throw FFMS_Exception(error_source, FFMS_ERROR_NO_FILE,
			"Failed to open '" + this->filename + "'");
}
Exemple #24
0
void FFMS_AudioSource::SetOutputFormat(const FFMS_ResampleOptions *opt) {
    if (!Cache.empty())
        throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_USER,
                             "Cannot change the output format after audio decoding has begun");

    if (opt->SampleRate != AP.SampleRate)
        throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
                             "Sample rate changes are currently unsupported.");

#ifndef WITH_AVRESAMPLE
    if (opt->SampleFormat != AP.SampleFormat || opt->SampleRate != AP.SampleRate || opt->ChannelLayout != AP.ChannelLayout)
        throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
                             "FFMS was not built with resampling enabled. The only supported conversion is interleaving planar audio.");
#endif

    BytesPerSample = av_get_bytes_per_sample(static_cast<AVSampleFormat>(opt->SampleFormat)) * av_get_channel_layout_nb_channels(opt->ChannelLayout);
    NeedsResample =
        opt->SampleFormat != (int)CodecContext->sample_fmt ||
        opt->SampleRate != AP.SampleRate ||
        opt->ChannelLayout != AP.ChannelLayout ||
        opt->ForceResample;

#ifdef WITH_AVRESAMPLE
    if (!NeedsResample) return;

    std::auto_ptr<FFMS_ResampleOptions> oldOptions(ReadOptions(ResampleContext, resample_options));
    SetOptions(opt, ResampleContext, resample_options);
    av_opt_set_int(ResampleContext, "in_sample_rate", AP.SampleRate, 0);
    av_opt_set_int(ResampleContext, "in_sample_fmt", CodecContext->sample_fmt, 0);
    av_opt_set_int(ResampleContext, "in_channel_layout", AP.ChannelLayout, 0);

    if (avresample_open(ResampleContext)) {
        SetOptions(oldOptions.get(), ResampleContext, resample_options);
        if (avresample_open(ResampleContext) < 0)
            throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNKNOWN,
                                 "Could not re-open old avresample context");
        else
            throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNKNOWN,
                                 "Could not open avresample context");
    }
#endif
}
Exemple #25
0
FFMS_API(int) FFMS_IndexBelongsToFile(FFMS_Index *Index, const char *SourceFile, FFMS_ErrorInfo *ErrorInfo) {
	ClearErrorInfo(ErrorInfo);
	try {
		if (!Index->CompareFileSignature(SourceFile))
			throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_MISMATCH,
				"The index does not belong to the file");
	} catch (FFMS_Exception &e) {
		return e.CopyOut(ErrorInfo);
	}
	return FFMS_ERROR_SUCCESS;
}
Exemple #26
0
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];
}
Exemple #27
0
TrackCompressionContext::TrackCompressionContext(MatroskaFile *MF, TrackInfo *TI, unsigned int Track)
: CS(NULL)
, CompressedPrivateData(NULL)
, CompressedPrivateDataSize(0)
, CompressionMethod(TI->CompMethod)
{
	if (CompressionMethod == COMP_ZLIB) {
		char ErrorMessage[512];
		CS = cs_Create(MF, Track, ErrorMessage, sizeof(ErrorMessage));
		if (CS == NULL) {
			std::ostringstream buf;
			buf << "Can't create MKV track decompressor: " << ErrorMessage;
			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str());
		}
	} else if (CompressionMethod == COMP_PREPEND) {
		CompressedPrivateData		= TI->CompMethodPrivate;
		CompressedPrivateDataSize	= TI->CompMethodPrivateSize;
	} else {
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			"Can't create MKV track decompressor: unknown or unsupported compression method");
	}
}
Exemple #28
0
FFMS_API(int) FFMS_GetFirstIndexedTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo) {
	ClearErrorInfo(ErrorInfo);
	for (int i = 0; i < static_cast<int>(Index->size()); i++)
		if ((*Index)[i].TT == TrackType && !(*Index)[i].empty())
			return i;
	try {
		throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_NOT_AVAILABLE,
			"No suitable, indexed track found");
	} catch (FFMS_Exception &e) {
		e.CopyOut(ErrorInfo);
		return -1;
	}
}
Exemple #29
0
FFMatroskaAudio::FFMatroskaAudio(const char *SourceFile, int Track, FFMS_Index &Index, int DelayMode)
: FFMS_AudioSource(SourceFile, Index, Track)
, TI(NULL)
{
	if (!(MC.ST.fp = ffms_fopen(SourceFile, "rb")))
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("Can't open '") + SourceFile + "': " + strerror(errno));

	setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);

	if (!(MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage))))
		throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
			std::string("Can't parse Matroska file: ") + ErrorMessage);

	TI = mkv_GetTrackInfo(MF, Track);
	assert(TI);

	if (TI->CompEnabled)
		TCC.reset(new TrackCompressionContext(MF, TI, Track));

	CodecContext.reset(avcodec_alloc_context3(NULL), DeleteMatroskaCodecContext);
	assert(CodecContext);

	AVCodec *Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate, 0, TI->AV.Audio.BitDepth));
	if (!Codec) {
		mkv_Close(MF);
		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Audio codec not found");
	}

	InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext);

	if (avcodec_open2(CodecContext, Codec, NULL) < 0) {
		mkv_Close(MF);
		throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Could not open audio codec");
	}

	Init(Index, DelayMode);
}
Exemple #30
0
void FlushBuffers(AVCodecContext *CodecContext) {
	if (CodecContext->codec->flush)
		avcodec_flush_buffers(CodecContext);
	else {
		// If the codec doesn't have flush(), it might not need it... or it
		// might need it and just not implement it as in the case of VC-1, so
		// close and reopen the codec
		const AVCodec *codec = CodecContext->codec;
		avcodec_close(CodecContext);
		// Whether or not codec is const varies between versions
		if (avcodec_open2(CodecContext, const_cast<AVCodec *>(codec), 0) < 0)
			throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_CODEC,
				"Couldn't re-open codec.");
	}
}