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;
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;
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,14 +79,9 @@ 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.
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.
</p>
<p>
@ -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