FFmpegSource 1.16 + minor fix

Originally committed to SVN as r2151.
This commit is contained in:
Fredrik Mellbin 2008-03-28 21:14:06 +00:00
parent b7af0a06d5
commit d6e76cee4f
13 changed files with 114 additions and 310 deletions

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -29,7 +29,7 @@ int FFBase::FrameFromDTS(int64_t ADTS) {
int FFBase::ClosestFrameFromDTS(int64_t ADTS) {
int Frame = 0;
int64_t BestDiff = 0xFFFFFFFFFFFFFFLL;
int64_t BestDiff = 0xFFFFFFFFFFFFFFLL; // big number
for (int i = 0; i < (int)Frames.size(); i++) {
int64_t CurrentDiff = FFABS(Frames[i].DTS - ADTS);
if (CurrentDiff < BestDiff) {
@ -113,83 +113,6 @@ bool FFBase::SaveTimecodesToFile(const char *ATimecodeFile, int64_t ScaleD, int6
return true;
}
#ifdef FLAC_CACHE
static FLAC__StreamDecoderReadStatus FLACStreamDecoderReadCallback(const FLAC__StreamDecoder *ADecoder, FLAC__byte ABuffer[], size_t *ABytes, FFBase *AOwner) {
if(*ABytes > 0) {
*ABytes = fread(ABuffer, sizeof(FLAC__byte), *ABytes, AOwner->FCFile);
if(ferror(AOwner->FCFile))
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
else if(*ABytes == 0)
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
else
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
} else {
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
}
static FLAC__StreamDecoderSeekStatus FLACStreamDecoderSeekCallback(const FLAC__StreamDecoder *ADecoder, FLAC__uint64 AAbsoluteByteOffset, FFBase *AOwner) {
if(_fseeki64(AOwner->FCFile, AAbsoluteByteOffset, SEEK_SET) < 0)
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
else
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
static FLAC__StreamDecoderTellStatus FLACStreamDecoderTellCallback(const FLAC__StreamDecoder *ADecoder, FLAC__uint64 *AAbsoluteByteOffset, FFBase *AOwner) {
__int64 Pos;
if ((Pos = _ftelli64(AOwner->FCFile)) < 0) {
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
} else {
*AAbsoluteByteOffset = (FLAC__uint64)Pos;
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
}
static FLAC__StreamDecoderLengthStatus FLACStreamDecoderLengthCallback(const FLAC__StreamDecoder *ADecoder, FLAC__uint64 *AStreamLength, FFBase *AOwner) {
__int64 OriginalPos;
__int64 Length;
if ((OriginalPos = _ftelli64(AOwner->FCFile)) < 0)
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
_fseeki64(AOwner->FCFile, 0, SEEK_END);
if ((Length = _ftelli64(AOwner->FCFile)) < 0)
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
_fseeki64(AOwner->FCFile, OriginalPos, SEEK_SET);
*AStreamLength = Length;
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
static FLAC__bool FLACStreamDecoderEofCallback(const FLAC__StreamDecoder *ADecoder, FFBase *AOwner) {
return feof(AOwner->FCFile) ? true : false;
}
static FLAC__StreamDecoderWriteStatus FLACStreamDecoderWriteCallback(const FLAC__StreamDecoder *ADecoder, const FLAC__Frame *AFrame, const FLAC__int32 *const ABuffer[], FFBase *AOwner) {
unsigned Blocksize = AFrame->header.blocksize;
const VideoInfo VI = AOwner->GetVideoInfo();
int16_t *Buffer = (int16_t *)AOwner->FCBuffer;
int j = 0;
while (AOwner->FCCount > 0 && Blocksize > 0) {
for (int i = 0; i < VI.nchannels; i++)
*Buffer++ = ABuffer[i][j];
j++;
AOwner->FCCount--;
Blocksize--;
}
AOwner->FCBuffer = Buffer;
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static void FLACStreamDecoderMetadataCallback(const FLAC__StreamDecoder *ADecoder, const FLAC__StreamMetadata *AMetadata, FFBase *AOwner) {
AOwner->FCError = (AMetadata->data.stream_info.total_samples <= 0);
}
static void FLACStreamDecoderErrorCallback(const FLAC__StreamDecoder *ADecoder, FLAC__StreamDecoderErrorStatus AStatus, FFBase *AOwner) {
AOwner->FCError = true;
}
#endif // FLAC_CACHE
bool FFBase::OpenAudioCache(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env) {
char DefaultCacheFilename[1024];
sprintf(DefaultCacheFilename, "%s.ffa%dcache", ASource, AAudioTrack);
@ -197,7 +120,7 @@ bool FFBase::OpenAudioCache(const char *AAudioCacheFile, const char *ASource, in
AAudioCacheFile = DefaultCacheFilename;
// Is an empty file?
FCFile = fopen(AAudioCacheFile, "rb");
FILE *FCFile = fopen(AAudioCacheFile, "rb");
int64_t CacheSize;
if (FCFile) {
_fseeki64(FCFile, 0, SEEK_END);
@ -212,29 +135,6 @@ bool FFBase::OpenAudioCache(const char *AAudioCacheFile, const char *ASource, in
return false;
}
#ifdef FLAC_CACHE
// is FLAC?
FLACAudioCache = FLAC__stream_decoder_new();
if (FLAC__stream_decoder_init_stream(FLACAudioCache,
&(FLAC__StreamDecoderReadCallback)FLACStreamDecoderReadCallback,
&(FLAC__StreamDecoderSeekCallback)FLACStreamDecoderSeekCallback,
&(FLAC__StreamDecoderTellCallback)FLACStreamDecoderTellCallback,
&(FLAC__StreamDecoderLengthCallback)FLACStreamDecoderLengthCallback,
&(FLAC__StreamDecoderEofCallback)FLACStreamDecoderEofCallback,
&(FLAC__StreamDecoderWriteCallback)FLACStreamDecoderWriteCallback,
&(FLAC__StreamDecoderMetadataCallback)FLACStreamDecoderMetadataCallback, &(FLAC__StreamDecoderErrorCallback)FLACStreamDecoderErrorCallback, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK) {
FCError = true;
FLAC__stream_decoder_process_until_end_of_metadata(FLACAudioCache);
if (!FCError) {
VI.num_audio_samples = FLAC__stream_decoder_get_total_samples(FLACAudioCache);
AudioCacheType = acFLAC;
return true;
}
}
FLAC__stream_decoder_delete(FLACAudioCache);
FLACAudioCache = NULL;
#endif // FLAC_CACHE
// Raw audio
VI.num_audio_samples = VI.AudioSamplesFromBytes(CacheSize);
AudioCacheType = acRaw;
@ -243,64 +143,6 @@ bool FFBase::OpenAudioCache(const char *AAudioCacheFile, const char *ASource, in
return true;
}
#ifdef FLAC_CACHE
static FLAC__StreamEncoderWriteStatus FLACStreamEncoderWriteCallback(const FLAC__StreamEncoder *ASncoder, const FLAC__byte ABuffer[], size_t ABytes, unsigned ABamples, unsigned ACurrentFrame, FFBase *AOwner) {
fwrite(ABuffer, sizeof(FLAC__byte), ABytes, AOwner->FCFile);
if(ferror(AOwner->FCFile))
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
else
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
static FLAC__StreamEncoderSeekStatus FLACStreamEncoderSeekCallback(const FLAC__StreamEncoder *AEncoder, FLAC__uint64 AAbsoluteByteOffset, FFBase *AOwner) {
if(_fseeki64(AOwner->FCFile, AAbsoluteByteOffset, SEEK_SET) < 0)
return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
else
return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
}
static FLAC__StreamEncoderTellStatus FLACStreamEncoderTellCallback(const FLAC__StreamEncoder *AEncoder, FLAC__uint64 *AAbsoluteByteOffset, FFBase *AOwner) {
__int64 Pos;
if((Pos = _ftelli64(AOwner->FCFile)) < 0) {
return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
} else {
*AAbsoluteByteOffset = (FLAC__uint64)Pos;
return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
}
}
FLAC__StreamEncoder *FFBase::NewFLACCacheWriter(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, int ACompression, IScriptEnvironment *Env) {
char DefaultCacheFilename[1024];
sprintf(DefaultCacheFilename, "%s.ffa%dcache", ASource, AAudioTrack);
if (!strcmp(AAudioCacheFile, ""))
AAudioCacheFile = DefaultCacheFilename;
FCFile = fopen(AAudioCacheFile, "wb");
if (!FCFile)
Env->ThrowError("FFmpegSource: Failed to open '%s' for writing", AAudioCacheFile);
FLAC__StreamEncoder *FSE;
FSE = FLAC__stream_encoder_new();
FLAC__stream_encoder_set_channels(FSE, VI.nchannels);
FLAC__stream_encoder_set_bits_per_sample(FSE, VI.BytesPerChannelSample() * 8);
FLAC__stream_encoder_set_sample_rate(FSE, VI.audio_samples_per_second);
FLAC__stream_encoder_set_compression_level(FSE, ACompression);
if (FLAC__stream_encoder_init_stream(FSE, &(FLAC__StreamEncoderWriteCallback)FLACStreamEncoderWriteCallback,
&(FLAC__StreamEncoderSeekCallback)FLACStreamEncoderSeekCallback,
&(FLAC__StreamEncoderTellCallback)FLACStreamEncoderTellCallback, NULL, this)
!= FLAC__STREAM_ENCODER_INIT_STATUS_OK)
Env->ThrowError("FFmpegSource: Failed to initialize the FLAC encoder for '%s'", AAudioCacheFile);
return FSE;
}
void FFBase::CloseFLACCacheWriter(FLAC__StreamEncoder *AFSE) {
FLAC__stream_encoder_finish(AFSE);
FLAC__stream_encoder_delete(AFSE);
fclose(FCFile);
FCFile = NULL;
}
#endif // FLAC_CACHE
FILE *FFBase::NewRawCacheWriter(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env) {
char DefaultCacheFilename[1024];
sprintf(DefaultCacheFilename, "%s.ffa%dcache", ASource, AAudioTrack);
@ -325,7 +167,7 @@ void FFBase::InitPP(int AWidth, int AHeight, const char *APPString, int AQuality
Env->ThrowError("FFmpegSource: Quality is out of range");
// Unsafe?
PPMode = pp_get_mode_by_name_and_quality((char *)APPString, AQuality);
PPMode = pp_get_mode_by_name_and_quality(APPString, AQuality);
if (!PPMode)
Env->ThrowError("FFmpegSource: Invalid postprocesing settings");
@ -379,7 +221,7 @@ PVideoFrame FFBase::OutputFrame(AVFrame *AFrame, IScriptEnvironment *Env) {
AVPicture *SrcPicture = (AVPicture *)AFrame;
if (PPContext) {
pp_postprocess(AFrame->data, AFrame->linesize, PPPicture.data, PPPicture.linesize, VI.width, VI.height, AFrame->qscale_table, AFrame->qstride, PPMode, PPContext, AFrame->pict_type | (AFrame->qscale_type ? PP_PICT_TYPE_QP2 : 0));
pp_postprocess(const_cast<const uint8_t **>(AFrame->data), AFrame->linesize, PPPicture.data, PPPicture.linesize, VI.width, VI.height, AFrame->qscale_table, AFrame->qstride, PPMode, PPContext, AFrame->pict_type | (AFrame->qscale_type ? PP_PICT_TYPE_QP2 : 0));
SrcPicture = &PPPicture;
}
@ -416,15 +258,7 @@ PVideoFrame FFBase::OutputFrame(AVFrame *AFrame, IScriptEnvironment *Env) {
void FFBase::GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironment* Env) {
if (AudioCacheType == acRaw) {
_fseeki64(RawAudioCache, VI.BytesFromAudioSamples(Start), SEEK_SET);
fread(Buf, 1, (size_t)VI.BytesFromAudioSamples(Count), RawAudioCache);
#ifdef FLAC_CACHE
} else if (AudioCacheType == acFLAC) {
FCCount = Count;
FCBuffer = Buf;
FLAC__stream_decoder_seek_absolute(FLACAudioCache, Start);
while (FCCount > 0)
FLAC__stream_decoder_process_single(FLACAudioCache);
#endif // FLAC_CACHE
fread(Buf, 1, static_cast<size_t>(VI.BytesFromAudioSamples(Count)), RawAudioCache);
} else {
Env->ThrowError("FFmpegSource: Audio requested but none available");
}
@ -433,18 +267,12 @@ void FFBase::GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironmen
FFBase::FFBase() {
memset(&VI, 0, sizeof(VI));
AudioCacheType = acNone;
FCError = false;
RawAudioCache = NULL;
PPContext = NULL;
PPMode = NULL;
SWS = NULL;
LastFrameNum = -1;
DecodingBuffer = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE];
#ifdef FLAC_CACHE
FLACAudioCache = NULL;
FLACBuffer = new FLAC__int32[AVCODEC_MAX_AUDIO_FRAME_SIZE];
#endif // FLAC_CACHE
FCFile = NULL;
ConvertToFormat = PIX_FMT_NONE;
memset(&PPPicture, 0, sizeof(PPPicture));
DecodeFrame = avcodec_alloc_frame();
@ -454,15 +282,6 @@ FFBase::~FFBase() {
delete [] DecodingBuffer;
if (RawAudioCache)
fclose(RawAudioCache);
#ifdef FLAC_CACHE
delete [] FLACBuffer;
if (FLACAudioCache) {
FLAC__stream_decoder_finish(FLACAudioCache);
FLAC__stream_decoder_delete(FLACAudioCache);
}
#endif // FLAC_CACHE
if (FCFile)
fclose(FCFile);
if (SWS)
sws_freeContext(SWS);
if (PPMode)

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -45,8 +45,8 @@ int FFMatroskaSource::GetTrackIndex(int Index, unsigned char ATrackType, IScript
}
FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes,
bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString,
int AQuality, IScriptEnvironment* Env, FrameInfoVector *AFrames) {
bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString,
int AQuality, int AThreads, IScriptEnvironment* Env, FrameInfoVector *AFrames) {
AFrames = &Frames;
CurrentFrame = 0;
@ -105,6 +105,7 @@ FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAu
VideoCodecContext = avcodec_alloc_context();
VideoCodecContext->extradata = (uint8_t *)VideoTI->CodecPrivate;
VideoCodecContext->extradata_size = VideoTI->CodecPrivateSize;
VideoCodecContext->thread_count = AThreads;
VideoCodec = avcodec_find_decoder(MatroskaToFFCodecID(VideoTI));
if (VideoCodec == NULL)
@ -184,11 +185,11 @@ FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAu
VI.audio_samples_per_second = AudioCodecContext->sample_rate;
switch (AudioCodecContext->sample_fmt) {
case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; AACCompression = -1; break;
case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; break;
case SAMPLE_FMT_S16: VI.sample_type = SAMPLE_INT16; break;
case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; AACCompression = -1; break;
case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; AACCompression = -1; break;
case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; AACCompression = -1; break;
case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; break;
case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; break;
case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; break;
default:
Env->ThrowError("FFmpegSource: Unsupported/unknown sample format");
}
@ -202,20 +203,11 @@ FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAu
// Needs to be indexed?
if (!ACacheIsValid || !VCacheIsValid) {
#ifdef FLAC_CACHE
FLAC__StreamEncoder *FSE = NULL;
#endif // FLAC_CACHE
FILE *RawCache = NULL;
if (!ACacheIsValid)
if (AACCompression >= 0)
AudioCacheType = acFLAC;
else
AudioCacheType = acRaw;
switch (AudioCacheType) {
#ifdef FLAC_CACHE
case acFLAC: FSE = NewFLACCacheWriter(AAudioCache, ASource, AudioTrack, AACCompression, Env); break;
#endif // FLAC_CACHE
case acRaw: RawCache = NewRawCacheWriter(AAudioCache, ASource, AudioTrack, Env); break;
}
@ -244,21 +236,12 @@ FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAu
if (AudioCacheType == acRaw) {
fwrite(DecodingBuffer, 1, TempOutputBufSize, RawCache);
#ifdef FLAC_CACHE
} else if (AudioCacheType == acFLAC) {
for (int i = 0; i < DecodedSamples * VI.nchannels; i++)
FLACBuffer[i] = ((int16_t *)DecodingBuffer)[i];
FLAC__stream_encoder_process_interleaved(FSE, FLACBuffer, DecodedSamples);
#endif // FLAC_CACHE
}
}
}
if (!ACacheIsValid) {
switch (AudioCacheType) {
#ifdef FLAC_CACHE
case acFLAC: CloseFLACCacheWriter(FSE); break;
#endif // FLAC_CACHE
case acRaw: CloseRawCacheWriter(RawCache); break;
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -45,8 +45,8 @@ int FFmpegSource::GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironm
FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes,
bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString,
int AQuality, int ASeekMode, IScriptEnvironment *Env, FrameInfoVector *AFrames) {
bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString,
int AQuality, int AThreads, int ASeekMode, IScriptEnvironment *Env, FrameInfoVector *AFrames) {
AFrames = &Frames;
CurrentFrame = 0;
@ -79,6 +79,7 @@ FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack
VCacheIsValid = LoadFrameInfoFromFile(AVideoCache, ASource, VideoTrack);
VideoCodecContext = FormatContext->streams[VideoTrack]->codec;
VideoCodecContext->thread_count = AThreads;
VideoCodec = avcodec_find_decoder(VideoCodecContext->codec_id);
if (VideoCodec == NULL)
@ -124,11 +125,11 @@ FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack
Env->ThrowError("FFmpegSource: Could not open audio codec");
switch (AudioCodecContext->sample_fmt) {
case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; AACCompression = -1; break;
case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; break;
case SAMPLE_FMT_S16: VI.sample_type = SAMPLE_INT16; break;
case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; AACCompression = -1; break;
case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; AACCompression = -1; break;
case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; AACCompression = -1; break;
case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; break;
case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; break;
case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; break;
default:
Env->ThrowError("FFmpegSource: Unsupported/unknown sample format");
}
@ -144,20 +145,11 @@ FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack
// Needs to be indexed?
if (!ACacheIsValid || !VCacheIsValid) {
#ifdef FLAC_CACHE
FLAC__StreamEncoder *FSE = NULL;
#endif // FLAC_CACHE
FILE *RawCache = NULL;
if (!ACacheIsValid)
if (AACCompression >= 0)
AudioCacheType = acFLAC;
else
AudioCacheType = acRaw;
switch (AudioCacheType) {
#ifdef FLAC_CACHE
case acFLAC: FSE = NewFLACCacheWriter(AAudioCache, ASource, AudioTrack, AACCompression, Env); break;
#endif // FLAC_CACHE
case acRaw: RawCache = NewRawCacheWriter(AAudioCache, ASource, AudioTrack, Env); break;
}
@ -184,12 +176,6 @@ FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack
if (AudioCacheType == acRaw) {
fwrite(DecodingBuffer, 1, TempOutputBufSize, RawCache);
#ifdef FLAC_CACHE
} else if (AudioCacheType == acFLAC) {
for (int i = 0; i < DecodedSamples * VI.nchannels; i++)
FLACBuffer[i] = ((int16_t *)DecodingBuffer)[i];
FLAC__stream_encoder_process_interleaved(FSE, FLACBuffer, DecodedSamples);
#endif // FLAC_CACHE
}
}
}
@ -199,9 +185,6 @@ FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack
if (!ACacheIsValid) {
switch (AudioCacheType) {
#ifdef FLAC_CACHE
case acFLAC: CloseFLACCacheWriter(FSE); break;
#endif // FLAC_CACHE
case acRaw: CloseRawCacheWriter(RawCache); break;
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -21,10 +21,6 @@
#ifndef FFMPEGSOURCE_H
#define FFMPEGSOURCE_H
#ifndef NO_FLAC_CACHE
//#define FLAC_CACHE
#endif
#include <windows.h>
#include <stdio.h>
#include <vector>
@ -35,16 +31,11 @@
#include <fcntl.h>
#include <io.h>
#ifdef FLAC_CACHE
#include <stream_decoder.h>
#include <stream_encoder.h>
#endif // FLAC_CACHE
extern "C" {
#include <ffmpeg\avformat.h>
#include <ffmpeg\avcodec.h>
#include <ffmpeg\swscale.h>
#include <postproc\postprocess.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libpostproc/postprocess.h>
#include "stdiostream.h"
}
@ -52,7 +43,7 @@ extern "C" {
#include "MatroskaParser.h"
#include "avisynth.h"
enum AudioCacheFormat {acNone, acRaw, acFLAC};
enum AudioCacheFormat {acNone, acRaw};
struct FrameInfo {
int64_t DTS;
@ -111,11 +102,6 @@ protected:
int LastFrameNum;
uint8_t *DecodingBuffer;
#ifdef FLAC_CACHE
FLAC__StreamDecoder *FLACAudioCache;
FLAC__int32 *FLACBuffer;
#endif // FLAC_CACHE
FrameInfoVector Frames;
int FindClosestKeyFrame(int AFrame);
@ -126,10 +112,6 @@ protected:
bool SaveTimecodesToFile(const char *ATimecodeFile, int64_t ScaleD, int64_t ScaleN);
bool OpenAudioCache(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env);
#ifdef FLAC_CACHE
FLAC__StreamEncoder *FFBase::NewFLACCacheWriter(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, int ACompression, IScriptEnvironment *Env);
void FFBase::CloseFLACCacheWriter(FLAC__StreamEncoder *AFSE);
#endif // FLAC_CACHE
FILE *FFBase::NewRawCacheWriter(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env);
void FFBase::CloseRawCacheWriter(FILE *ARawCache);
@ -137,11 +119,6 @@ protected:
void SetOutputFormat(int ACurrentFormat, IScriptEnvironment *Env);
PVideoFrame OutputFrame(AVFrame *AFrame, IScriptEnvironment *Env);
public:
// FLAC decoder variables, have to be public
FILE *FCFile;
__int64 FCCount;
void *FCBuffer;
bool FCError;
FFBase();
~FFBase();
@ -164,7 +141,7 @@ private:
int GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironment *Env);
int DecodeNextFrame(AVFrame *Frame, int64_t *DTS);
public:
FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString, int AQuality, int ASeekMode, IScriptEnvironment *Env, FrameInfoVector *AFrames);
FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString, int AQuality, int AThreads, int ASeekMode, IScriptEnvironment *Env, FrameInfoVector *AFrames);
~FFmpegSource();
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *Env);
};
@ -185,7 +162,7 @@ private:
int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, IScriptEnvironment* Env);
int GetTrackIndex(int Index, unsigned char ATrackType, IScriptEnvironment *Env);
public:
FFMatroskaSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString, int AQuality, IScriptEnvironment *Env, FrameInfoVector *AFrames);
FFMatroskaSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString, int AQuality, int AThreads, IScriptEnvironment *Env, FrameInfoVector *AFrames);
~FFMatroskaSource();
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *Env);
};

View file

@ -28,7 +28,7 @@ Loads video files without sucking
<h2>Usage</h2>
<p>
<b>FFmpegSource(string source, int vtrack = -1, int atrack = -2, string timecodes, bool vcache = true, string vcachefile, string acachefile, int accompression = -1, string pp, int ppquality = 6, int seekmode = 1)</b><br />
<b>FFmpegSource(string source, int vtrack = -1, int atrack = -2, string timecodes, bool vcache = true, string vcachefile, string acachefile, string pp, int ppquality = 6, int threads = 1, int seekmode = 1)</b><br />
</p>
<p>
@ -45,7 +45,7 @@ Experimental, may or may not be accurate enough for real usage.
<p>
<b>FFPP(clip, string pp, int ppquality = 6)</b><br />
Separate postprocessing which also seems to include a few simple deinterlacers
Separate postprocessing which also seems to include a few simple deinterlacers
</p>
<p>
@ -79,11 +79,6 @@ Separate postprocessing which also seems to include a few simple deinterlacers
Specifies the file to store the demuxed audio stream in. Only used by FFAudioSource if the stream isn't matroska. If nothing is specified (source).ffasd(tracknumber)cache is used.
</p>
<p>
<b>accompression:</b>
Audio cache compression, -1 means raw audio and 0-8 uses FLAC with that compression level.
</p>
<p>
<b>pp:</b>
See the table below for a full description, an empty string means no processing. It is recommended to avoid the autoq option since it's currently unknown what effect it will have on the processing.
@ -94,6 +89,11 @@ Separate postprocessing which also seems to include a few simple deinterlacers
The quality to use for the specified postprocessing. Valid values are 0-6 where 0 usually means that no actual processing is done.
</p>
<p>
<b>threads:</b>
Sets the number of decoder threads used, ignored if the used decoder doesn't implement it.
</p>
<p>
<b>seekmode:</b>
Force how seeking is handled, has no effect on matroska files which always use the equivalent of seekmode=1<br />
@ -154,16 +154,32 @@ tn:64:128:256
<p><b>FFmpeg svn</b> from http://ffmpeg.mplayerhq.hu/</p>
<p><b>FLAC (optional)</b> from http://flac.sourceforge.net/ (static library seems to be broken)</p>
<p><b>Required FFmpeg Configuration:</b>
./configure --enable-shared --disable-static --enable-memalign-hack --enable-gpl --enable-swscaler</p>
./configure --enable-memalign-hack --enable-gpl --enable-swscale --enable-postproc
<p><b>Suggested Additional Options:</b>
--disable-encoders --disable-muxers --enable-small</p>
--enable-w32threads --disable-encoders --disable-muxers --enable-small --enable-libfaad --disable-debug</p>
<p>
Note that --enable-w32threads is required for multithreaded decoding to work.
</p>
<h2>Changes</h2>
<ul>
<li>1.17<ul>
<li>Updated FFmpeg to rev X</li>
</ul></li>
<li>1.16<ul>
<li>Added many new and missing matroska codec ids</li>
<li>Added threads argument to set the number of decoding threads used</li>
<li>Completely removed FLAC cache</li>
<li>Updated FFmpeg to rev 12382</li>
</ul></li>
<li>1.15<ul>
<li>Updated FFmpeg to rev 11518</li>
</ul></li>
<li>1.14<ul>
<li>If the output colorspace is YV12 or YUY2 the width and height may be automatically cropped by one pixel to make it an even number</li>
<li>FLAC cache is disabled because the static FLAC lib doesn't want to link</li>
@ -172,8 +188,6 @@ tn:64:128:256
<li>Updated FFmpeg to rev 11413</li>
</ul></li>
<h2>Changes</h2>
<ul>
<li>1.13<ul>
<li>Now always sorts the output timecodes so native avc in mkv won't have out of order values</li>
<li>Fixed the missing '# timecode format v2' line in saved timecode files</li>

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -75,7 +75,7 @@ PVideoFrame FFPP::GetFrame(int n, IScriptEnvironment* Env) {
PVideoFrame Dst = Env->NewVideoFrame(vi);
if (vi.IsYV12()) {
uint8_t *SrcData[3] = {(uint8_t *)Src->GetReadPtr(PLANAR_Y), (uint8_t *)Src->GetReadPtr(PLANAR_U), (uint8_t *)Src->GetReadPtr(PLANAR_V)};
const uint8_t *SrcData[3] = {(uint8_t *)Src->GetReadPtr(PLANAR_Y), (uint8_t *)Src->GetReadPtr(PLANAR_U), (uint8_t *)Src->GetReadPtr(PLANAR_V)};
int SrcStride[3] = {Src->GetPitch(PLANAR_Y), Src->GetPitch(PLANAR_U), Src->GetPitch(PLANAR_V)};
uint8_t *DstData[3] = {Dst->GetWritePtr(PLANAR_Y), Dst->GetWritePtr(PLANAR_U), Dst->GetWritePtr(PLANAR_V)};
int DstStride[3] = {Dst->GetPitch(PLANAR_Y), Dst->GetPitch(PLANAR_U), Dst->GetPitch(PLANAR_V)};
@ -86,7 +86,7 @@ PVideoFrame FFPP::GetFrame(int n, IScriptEnvironment* Env) {
int SrcStride[1] = {Src->GetPitch()};
sws_scale(SWSTo422P, SrcData, SrcStride, 0, vi.height, InputPicture.data, InputPicture.linesize);
pp_postprocess(InputPicture.data, InputPicture.linesize, OutputPicture.data, OutputPicture.linesize, vi.width, vi.height, NULL, 0, PPMode, PPContext, 0);
pp_postprocess(const_cast<const uint8_t **>(InputPicture.data), InputPicture.linesize, OutputPicture.data, OutputPicture.linesize, vi.width, vi.height, NULL, 0, PPMode, PPContext, 0);
uint8_t *DstData[1] = {Dst->GetWritePtr()};
int DstStride[1] = {Dst->GetPitch()};

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -64,9 +64,9 @@ AVSValue __cdecl CreateFFmpegSource(AVSValue Args, void* UserData, IScriptEnviro
bool VCache = Args[4].AsBool(true);
const char *VCacheFile = Args[5].AsString("");
const char *ACacheFile = Args[6].AsString("");
int ACCompression = Args[7].AsInt(-1);
const char *PPString = Args[8].AsString("");
int PPQuality = Args[9].AsInt(PP_QUALITY_MAX);
const char *PPString = Args[7].AsString("");
int PPQuality = Args[8].AsInt(PP_QUALITY_MAX);
int Threads = Args[9].AsInt(1);
int SeekMode = Args[10].AsInt(1);
if (VTrack <= -2 && ATrack <= -2)
@ -75,13 +75,8 @@ AVSValue __cdecl CreateFFmpegSource(AVSValue Args, void* UserData, IScriptEnviro
if (SeekMode < -1 || SeekMode > 3)
Env->ThrowError("FFmpegSource: Invalid seekmode selected");
#ifdef FLAC_CACHE
if (ACCompression < -1 || ACCompression > 8)
#else
if (ACCompression != -1)
#endif // FLAC_CACHE
Env->ThrowError("FFmpegSource: Invalid audio cache compression selected");
if (Threads < 1)
Env->ThrowError("FFmpegSource: Invalid thread count");
AVFormatContext *FormatContext;
@ -93,12 +88,12 @@ AVSValue __cdecl CreateFFmpegSource(AVSValue Args, void* UserData, IScriptEnviro
FrameInfoVector Frames;
if (IsMatroska) {
return new FFMatroskaSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, ACCompression, PPString, PPQuality, Env, &Frames);
return new FFMatroskaSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, PPString, PPQuality, Threads, Env, &Frames);
} else {
// Do a separate indexing pass, enjoy the constructor sideeffects
if (SeekMode == -1)
delete new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, ACCompression, PPString, PPQuality, -2, Env, &Frames);
return new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, ACCompression, PPString, PPQuality, SeekMode, Env, &Frames);
delete new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, PPString, PPQuality, Threads, -2, Env, &Frames);
return new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, PPString, PPQuality, Threads, SeekMode, Env, &Frames);
}
}
@ -138,7 +133,7 @@ AVSValue __cdecl CreateFFPP(AVSValue Args, void* UserData, IScriptEnvironment* E
}
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* Env) {
Env->AddFunction("FFmpegSource", "[source]s[vtrack]i[atrack]i[timecodes]s[vcache]b[vcachefile]s[acachefile]s[accompression]i[pp]s[ppquality]i[seekmode]i", CreateFFmpegSource, 0);
Env->AddFunction("FFmpegSource", "[source]s[vtrack]i[atrack]i[timecodes]s[vcache]b[vcachefile]s[acachefile]s[pp]s[ppquality]i[threads]i[seekmode]i", CreateFFmpegSource, 0);
Env->AddFunction("FFAudioSource", "[source]s[atrack]i[acachefile]s[ademuxedfile]s", CreateFFAudioSource, 0);
Env->AddFunction("FFPP", "c[pp]s[ppquality]i", CreateFFPP, 0);
return "FFmpegSource";

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -135,9 +135,9 @@ CodecID MatroskaToFFCodecID(TrackInfo *TI) {
case MAKEFOURCC('M', 'S', 'Z', 'H'):
return CODEC_ID_MSZH;
case MAKEFOURCC('Z', 'L', 'I', 'B'):
return CODEC_ID_FLV1;
case MAKEFOURCC('F', 'L', 'V', '1'):
return CODEC_ID_ZLIB;
case MAKEFOURCC('F', 'L', 'V', '1'):
return CODEC_ID_FLV1;
/*
case MAKEFOURCC('P', 'N', 'G', '1'):
return CODEC_ID_COREPNG;
@ -199,18 +199,33 @@ CodecID MatroskaToFFCodecID(TrackInfo *TI) {
default:
return CODEC_ID_NONE;
}
} else if (!strcmp(Codec, "V_MPEG4/ISO/AVC"))
return CODEC_ID_H264;
else if (!strcmp(Codec, "V_MPEG4/ISO/AP"))
return CODEC_ID_MPEG4;
else if (!strcmp(Codec, "V_MPEG4/ISO/ASP"))
return CODEC_ID_MPEG4;
else if (!strcmp(Codec, "V_MPEG4/ISO/SP"))
return CODEC_ID_MPEG4;
else if (!strcmp(Codec, "V_MPEG4/MS/V3"))
return CODEC_ID_MSMPEG4V3;
else if (!strcmp(Codec, "V_MPEG2"))
return CODEC_ID_MPEG2VIDEO;
else if (!strcmp(Codec, "V_MPEG1"))
return CODEC_ID_MPEG2VIDEO; // still not a typo
else if (!strcmp(Codec, "V_VC1"))
return CODEC_ID_VC1;
else if (!strcmp(Codec, "V_SNOW"))
return CODEC_ID_SNOW;
else if (!strcmp(Codec, "V_THEORA"))
return CODEC_ID_THEORA;
else if (!strcmp(Codec, "V_UNCOMPRESSED"))
return CODEC_ID_NONE; // bleh
else if (!strcmp(Codec, "V_QUICKTIME"))
return CODEC_ID_SVQ3;
else if (!strcmp(Codec, "V_CIPC"))
return CODEC_ID_NONE; // don't know, don't care
else if (!strncmp(Codec, "V_REAL/RV", 9)) {
switch (Codec[9]) {
case '1':
@ -227,6 +242,8 @@ CodecID MatroskaToFFCodecID(TrackInfo *TI) {
/* Audio Codecs */
} else if (!strcmp(Codec, "A_AC3"))
return CODEC_ID_AC3;
else if (!strcmp(Codec, "A_EAC3"))
return CODEC_ID_AC3;
else if (!strcmp(Codec, "A_MPEG/L3"))
return CODEC_ID_MP3;
else if (!strcmp(Codec, "A_MPEG/L2"))
@ -243,8 +260,20 @@ CodecID MatroskaToFFCodecID(TrackInfo *TI) {
case 32: return CODEC_ID_PCM_S32LE;
default: return CODEC_ID_NONE;
}
} else if (!strcmp(Codec, "A_PCM/INT/BIG")) {
switch (TI->AV.Audio.BitDepth) {
case 8: return CODEC_ID_PCM_S8;
case 16: return CODEC_ID_PCM_S16BE;
case 24: return CODEC_ID_PCM_S24BE;
case 32: return CODEC_ID_PCM_S32BE;
default: return CODEC_ID_NONE;
}
} else if (!strcmp(Codec, "A_PCM/FLOAT/IEEE"))
return CODEC_ID_NONE; // no float codec id?
else if (!strcmp(Codec, "A_FLAC"))
return CODEC_ID_FLAC;
else if (!strcmp(Codec, "A_MPC"))
return CODEC_ID_MUSEPACK8;
else if (!strcmp(Codec, "A_TTA1"))
return CODEC_ID_TTA;
else if (!strcmp(Codec, "A_WAVPACK4"))
@ -263,6 +292,10 @@ CodecID MatroskaToFFCodecID(TrackInfo *TI) {
return CODEC_ID_ATRAC3;
else if (!strncmp(Codec, "A_AAC", 5))
return CODEC_ID_AAC;
else if (!strcmp(Codec, "A_SPEEX"))
return CODEC_ID_SPEEX;
else if (!strcmp(Codec, "A_QUICKTIME"))
return CODEC_ID_NONE; // no
else if (!strcmp(Codec, "A_MS/ACM")) {
// nothing useful here anyway?
//#include "Mmreg.h"

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

View file

@ -1,4 +1,4 @@
// Copyright (c) 2007 Fredrik Mellbin
// Copyright (c) 2007-2008 Fredrik Mellbin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal