Updating ffms2 to r221 (2.12), step 1/3: sources

Originally committed to SVN as r3574.
This commit is contained in:
Karl Blomster 2009-09-26 21:56:15 +00:00
parent 8322981b47
commit 6fe92bce72
21 changed files with 1354 additions and 1139 deletions

View file

@ -21,6 +21,9 @@
#ifndef FFMS_H
#define FFMS_H
// Version format: major - minor - micro - bump
#define FFMS_VERSION ((2 << 24) | (11 << 16)| (0 << 8) | 5)
#include <stdint.h>
#ifdef __cplusplus
@ -43,11 +46,56 @@
# define FFMS_API(ret) EXTERN_C ret FFMS_CC
#endif
FFMS_CLASS_TYPE FFVideo;
FFMS_CLASS_TYPE FFAudio;
FFMS_CLASS_TYPE FFIndexer;
FFMS_CLASS_TYPE FFIndex;
FFMS_CLASS_TYPE FFTrack;
struct FFMS_ErrorInfo {
int ErrorType;
int SubType;
int BufferSize;
char *Buffer;
};
FFMS_CLASS_TYPE FFMS_VideoSource;
FFMS_CLASS_TYPE FFMS_AudioSource;
FFMS_CLASS_TYPE FFMS_Indexer;
FFMS_CLASS_TYPE FFMS_Index;
FFMS_CLASS_TYPE FFMS_Track;
enum FFMS_Errors {
// No error
FFMS_ERROR_SUCCESS = 0,
// Main types - where the error occurred
FFMS_ERROR_INDEX = 1,
FFMS_ERROR_INDEXING,
FFMS_ERROR_POSTPROCESSING,
FFMS_ERROR_SCALING,
FFMS_ERROR_DECODING,
FFMS_ERROR_SEEKING,
FFMS_ERROR_PARSER,
FFMS_ERROR_TRACK,
FFMS_ERROR_WAVE_WRITER,
FFMS_ERROR_CANCELLED,
// Subtypes - what caused the error
FFMS_ERROR_UNKNOWN = 20,
FFMS_ERROR_UNSUPPORTED,
FFMS_ERROR_FILE_READ,
FFMS_ERROR_FILE_WRITE,
FFMS_ERROR_NO_FILE,
FFMS_ERROR_VERSION,
FFMS_ERROR_ALLOCATION_FAILED,
FFMS_ERROR_INVALID_ARGUMENT,
FFMS_ERROR_CODEC,
FFMS_ERROR_NOT_AVAILABLE,
FFMS_ERROR_FILE_MISMATCH,
FFMS_ERROR_USER
};
enum FFMS_Sources {
FFMS_SOURCE_LAVF = 0x01,
FFMS_SOURCE_MATROSKA = 0x02,
FFMS_SOURCE_HAALIMPEG = 0x04,
FFMS_SOURCE_HAALIOGG = 0x08
};
enum FFMS_CPUFeatures {
FFMS_CPU_CAPS_MMX = 0x01,
@ -65,6 +113,13 @@ enum FFMS_SeekMode {
FFMS_SEEK_AGGRESSIVE = 3
};
enum FFMS_IndexErrorHandling {
FFMS_IEH_ABORT = 0,
FFMS_IEH_CLEAR_TRACK = 1,
FFMS_IEH_STOP_TRACK = 2,
FFMS_IEH_IGNORE = 3
};
enum FFMS_TrackType {
FFMS_TYPE_UNKNOWN = -1,
FFMS_TYPE_VIDEO,
@ -106,20 +161,20 @@ enum FFMS_AudioChannel {
};
enum FFMS_Resizers {
FFMS_RESIZER_FAST_BILINEAR = 0x01,
FFMS_RESIZER_BILINEAR = 0x02,
FFMS_RESIZER_BICUBIC = 0x04,
FFMS_RESIZER_X = 0x08,
FFMS_RESIZER_POINT = 0x10,
FFMS_RESIZER_AREA = 0x20,
FFMS_RESIZER_BICUBLIN = 0x40,
FFMS_RESIZER_GAUSS = 0x80,
FFMS_RESIZER_SINC = 0x100,
FFMS_RESIZER_LANCZOS = 0x200,
FFMS_RESIZER_SPLINE = 0x400
FFMS_RESIZER_FAST_BILINEAR = 0x0001,
FFMS_RESIZER_BILINEAR = 0x0002,
FFMS_RESIZER_BICUBIC = 0x0004,
FFMS_RESIZER_X = 0x0008,
FFMS_RESIZER_POINT = 0x0010,
FFMS_RESIZER_AREA = 0x0020,
FFMS_RESIZER_BICUBLIN = 0x0040,
FFMS_RESIZER_GAUSS = 0x0080,
FFMS_RESIZER_SINC = 0x0100,
FFMS_RESIZER_LANCZOS = 0x0200,
FFMS_RESIZER_SPLINE = 0x0400
};
struct FFAVFrame {
struct FFMS_Frame {
uint8_t *Data[4];
int Linesize[4];
int EncodedWidth;
@ -135,37 +190,37 @@ struct FFAVFrame {
char PictType;
};
struct FFTrackTimeBase {
struct FFMS_TrackTimeBase {
int64_t Num;
int64_t Den;
};
#define FFMS_FRAMEINFO_COMMON int64_t DTS; int RepeatPict; bool KeyFrame;
struct FFFrameInfo {
struct FFMS_FrameInfo {
FFMS_FRAMEINFO_COMMON
};
struct FFVideoProperties {
int Width;
int Height;
struct FFMS_VideoProperties {
int FPSDenominator;
int FPSNumerator;
int RFFDenominator;
int RFFNumerator;
int NumFrames;
int VPixelFormat;
int SARNum;
int SARDen;
int CropTop;
int CropBottom;
int CropLeft;
int CropRight;
int TopFieldFirst;
int ColorSpace; // same as in the MPEG-2 specs, see AVColorSpace in avcodec.h
int ColorRange; // 0=unspecified, 1=16-235, 2=0-255
double FirstTime;
double LastTime;
};
struct FFAudioProperties {
struct FFMS_AudioProperties {
int SampleFormat;
int SampleRate;
int BitsPerSample;
@ -177,47 +232,51 @@ struct FFAudioProperties {
};
typedef int (FFMS_CC *TIndexCallback)(int64_t Current, int64_t Total, void *ICPrivate);
typedef int (FFMS_CC *TAudioNameCallback)(const char *SourceFile, int Track, const FFAudioProperties *AP, char *FileName, int FNSize, void *Private);
typedef int (FFMS_CC *TAudioNameCallback)(const char *SourceFile, int Track, const FFMS_AudioProperties *AP, char *FileName, int FNSize, void *Private);
// Most functions return 0 on success
// Functions without error message output can be assumed to never fail in a graceful way
FFMS_API(void) FFMS_Init(int CPUFeatures);
FFMS_API(int) FFMS_GetLogLevel();
FFMS_API(void) FFMS_SetLogLevel(int Level);
FFMS_API(FFVideo *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize);
FFMS_API(FFAudio *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize);
FFMS_API(void) FFMS_DestroyVideoSource(FFVideo *V);
FFMS_API(void) FFMS_DestroyAudioSource(FFAudio *A);
FFMS_API(const FFVideoProperties *) FFMS_GetVideoProperties(FFVideo *V);
FFMS_API(const FFAudioProperties *) FFMS_GetAudioProperties(FFAudio *A);
FFMS_API(const FFAVFrame *) FFMS_GetFrame(FFVideo *V, int n, char *ErrorMsg, unsigned MsgSize);
FFMS_API(const FFAVFrame *) FFMS_GetFrameByTime(FFVideo *V, double Time, char *ErrorMsg, unsigned MsgSize);
FFMS_API(int) FFMS_GetAudio(FFAudio *A, void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize);
FFMS_API(int) FFMS_SetOutputFormatV(FFVideo *V, int64_t TargetFormats, int Width, int Height, int Resizer, char *ErrorMsg, unsigned MsgSize);
FFMS_API(void) FFMS_ResetOutputFormatV(FFVideo *V);
FFMS_API(void) FFMS_DestroyIndex(FFIndex *Index);
FFMS_API(int) FFMS_GetFirstTrackOfType(FFIndex *Index, int TrackType, char *ErrorMsg, unsigned MsgSize);
FFMS_API(int) FFMS_GetFirstIndexedTrackOfType(FFIndex *Index, int TrackType, char *ErrorMsg, unsigned MsgSize);
FFMS_API(int) FFMS_GetNumTracks(FFIndex *Index);
FFMS_API(int) FFMS_GetNumTracksI(FFIndexer *Indexer);
FFMS_API(int) FFMS_GetTrackType(FFTrack *T);
FFMS_API(int) FFMS_GetTrackTypeI(FFIndexer *Indexer, int Track);
FFMS_API(const char *) FFMS_GetCodecNameI(FFIndexer *Indexer, int Track);
FFMS_API(int) FFMS_GetNumFrames(FFTrack *T);
FFMS_API(const FFFrameInfo *) FFMS_GetFrameInfo(FFTrack *T, int Frame);
FFMS_API(FFTrack *) FFMS_GetTrackFromIndex(FFIndex *Index, int Track);
FFMS_API(FFTrack *) FFMS_GetTrackFromVideo(FFVideo *V);
FFMS_API(FFTrack *) FFMS_GetTrackFromAudio(FFAudio *A);
FFMS_API(const FFTrackTimeBase *) FFMS_GetTimeBase(FFTrack *T);
FFMS_API(int) FFMS_WriteTimecodes(FFTrack *T, const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize);
FFMS_API(FFIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize);
FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const FFAudioProperties *AP, char *FileName, int FNSize, void *Private);
FFMS_API(FFIndexer *) FFMS_CreateIndexer(const char *SourceFile, char *ErrorMsg, unsigned MsgSize);
FFMS_API(FFIndex *) FFMS_DoIndexing(FFIndexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize);
FFMS_API(void) FFMS_CancelIndexing(FFIndexer *Indexer);
FFMS_API(FFIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
FFMS_API(int) FFMS_IndexBelongsToFile(FFIndex *Index, const char *SourceFile, char *ErrorMsg, unsigned MsgSize);
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFIndex *Index, char *ErrorMsg, unsigned MsgSize);
FFMS_API(FFMS_VideoSource *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(FFMS_AudioSource *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(void) FFMS_DestroyVideoSource(FFMS_VideoSource *V);
FFMS_API(void) FFMS_DestroyAudioSource(FFMS_AudioSource *A);
FFMS_API(const FFMS_VideoProperties *) FFMS_GetVideoProperties(FFMS_VideoSource *V);
FFMS_API(const FFMS_AudioProperties *) FFMS_GetAudioProperties(FFMS_AudioSource *A);
FFMS_API(const FFMS_Frame *) FFMS_GetFrame(FFMS_VideoSource *V, int n, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(const FFMS_Frame *) FFMS_GetFrameByTime(FFMS_VideoSource *V, double Time, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_GetAudio(FFMS_AudioSource *A, void *Buf, int64_t Start, int64_t Count, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_SetOutputFormatV(FFMS_VideoSource *V, int64_t TargetFormats, int Width, int Height, int Resizer, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(void) FFMS_ResetOutputFormatV(FFMS_VideoSource *V);
FFMS_API(int) FFMS_SetPP(FFMS_VideoSource *V, const char *PP, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(void) FFMS_ResetPP(FFMS_VideoSource *V);
FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index);
FFMS_API(int) FFMS_GetFirstTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_GetFirstIndexedTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_GetNumTracks(FFMS_Index *Index);
FFMS_API(int) FFMS_GetNumTracksI(FFMS_Indexer *Indexer);
FFMS_API(int) FFMS_GetTrackType(FFMS_Track *T);
FFMS_API(int) FFMS_GetTrackTypeI(FFMS_Indexer *Indexer, int Track);
FFMS_API(const char *) FFMS_GetCodecNameI(FFMS_Indexer *Indexer, int Track);
FFMS_API(int) FFMS_GetNumFrames(FFMS_Track *T);
FFMS_API(const FFMS_FrameInfo *) FFMS_GetFrameInfo(FFMS_Track *T, int Frame);
FFMS_API(FFMS_Track *) FFMS_GetTrackFromIndex(FFMS_Index *Index, int Track);
FFMS_API(FFMS_Track *) FFMS_GetTrackFromVideo(FFMS_VideoSource *V);
FFMS_API(FFMS_Track *) FFMS_GetTrackFromAudio(FFMS_AudioSource *A);
FFMS_API(const FFMS_TrackTimeBase *) FFMS_GetTimeBase(FFMS_Track *T);
FFMS_API(int) FFMS_WriteTimecodes(FFMS_Track *T, const char *TimecodeFile, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(FFMS_Index *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const FFMS_AudioProperties *AP, char *FileName, int FNSize, void *Private);
FFMS_API(FFMS_Indexer *) FFMS_CreateIndexer(const char *SourceFile, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(FFMS_Index *) FFMS_DoIndexing(FFMS_Indexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(void) FFMS_CancelIndexing(FFMS_Indexer *Indexer);
FFMS_API(FFMS_Index *) FFMS_ReadIndex(const char *IndexFile, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_IndexBelongsToFile(FFMS_Index *Index, const char *SourceFile, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo);
FFMS_API(int) FFMS_GetPixFmt(const char *Name);
FFMS_API(int) FFMS_GetPresentSources();
FFMS_API(int) FFMS_GetEnabledSources();
#endif

View file

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffaudiosource.h"
#include "audiosource.h"
/* Audio Cache */
@ -93,15 +93,32 @@ int64_t TAudioCache::FillRequest(int64_t Start, int64_t Samples, uint8_t *Dst) {
return FFMIN(Ret, Start + Samples);
}
/* FFAudio base class */
/* FFMS_AudioSource base class */
FFAudio::FFAudio(const char *SourceFile, FFIndex *Index, char *ErrorMsg, unsigned MsgSize) : DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10) {
if (Index->CompareFileSignature(SourceFile, ErrorMsg, MsgSize))
throw ErrorMsg;
FFMS_AudioSource::FFMS_AudioSource(const char *SourceFile, FFMS_Index *Index, int Track) : DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10), CurrentSample(0) {
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");
CurrentSample = 0;
if (Index->at(Track).TT != FFMS_TYPE_AUDIO)
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
"Not an audio track");
if (Index[Track].size() == 0)
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");
}
FFAudio::~FFAudio() {
FFMS_AudioSource::~FFMS_AudioSource() {
}
void FFMS_AudioSource::GetAudioCheck(int64_t Start, int64_t Count) {
if (Start < 0 || Start + Count > AP.NumSamples)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_INVALID_ARGUMENT,
"Out of bounds audio samples requested");
}

View file

@ -68,63 +68,68 @@ public:
int64_t FillRequest(int64_t Start, int64_t Samples, uint8_t *Dst);
};
class FFAudio {
class FFMS_AudioSource {
friend class FFSourceResources<FFMS_AudioSource>;
protected:
TAudioCache AudioCache;
int64_t CurrentSample;
std::vector<uint8_t> DecodingBuffer;
FFTrack Frames;
FFMS_Track Frames;
AVCodecContext *CodecContext;
int AudioTrack;
FFAudioProperties AP;
FFMS_AudioProperties AP;
virtual void Free(bool CloseCodec) = 0;
public:
FFAudio(const char *SourceFile, FFIndex *Index, char *ErrorMsg, unsigned MsgSize);
virtual ~FFAudio();
FFTrack *GetFFTrack() { return &Frames; }
const FFAudioProperties& GetFFAudioProperties() { return AP; }
virtual int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize) = 0;
FFMS_AudioSource(const char *SourceFile, FFMS_Index *Index, int Track);
virtual ~FFMS_AudioSource();
FFMS_Track *GetTrack() { return &Frames; }
const FFMS_AudioProperties& GetAudioProperties() { return AP; }
virtual void GetAudio(void *Buf, int64_t Start, int64_t Count) = 0;
void GetAudioCheck(int64_t Start, int64_t Count);
};
class FFLAVFAudio : public FFAudio {
class FFLAVFAudio : public FFMS_AudioSource {
private:
AVFormatContext *FormatContext;
FFSourceResources<FFMS_AudioSource> Res;
int DecodeNextAudioBlock(int64_t *Count, char *ErrorMsg, unsigned MsgSize);
void DecodeNextAudioBlock(int64_t *Count);
void Free(bool CloseCodec);
public:
FFLAVFAudio(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize);
~FFLAVFAudio();
int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize);
FFLAVFAudio(const char *SourceFile, int Track, FFMS_Index *Index);
void GetAudio(void *Buf, int64_t Start, int64_t Count);
};
class FFMatroskaAudio : public FFAudio {
class FFMatroskaAudio : public FFMS_AudioSource {
private:
MatroskaFile *MF;
MatroskaReaderContext MC;
CompressedStream *CS;
char ErrorMessage[256];
FFSourceResources<FFMS_AudioSource> Res;
size_t PacketNumber;
int DecodeNextAudioBlock(int64_t *Count, int AudioBlock, char *ErrorMsg, unsigned MsgSize);
void DecodeNextAudioBlock(int64_t *Count);
void Free(bool CloseCodec);
public:
FFMatroskaAudio(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize);
~FFMatroskaAudio();
int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize);
FFMatroskaAudio(const char *SourceFile, int Track, FFMS_Index *Index);
void GetAudio(void *Buf, int64_t Start, int64_t Count);
};
#ifdef HAALISOURCE
class FFHaaliAudio : public FFAudio {
class FFHaaliAudio : public FFMS_AudioSource {
private:
CComPtr<IMMContainer> pMMC;
std::vector<uint8_t> CodecPrivate;
FFSourceResources<FFMS_AudioSource> Res;
void DecodeNextAudioBlock(int64_t *AFirstStartTime, int64_t *Count);
void Free(bool CloseCodec);
int DecodeNextAudioBlock(int64_t *AFirstStartTime, int64_t *Count, char *ErrorMsg, unsigned MsgSize);
public:
FFHaaliAudio(const char *SourceFile, int Track, FFIndex *Index, int SourceMode, char *ErrorMsg, unsigned MsgSize);
~FFHaaliAudio();
int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize);
FFHaaliAudio(const char *SourceFile, int Track, FFMS_Index *Index, enum FFMS_Sources SourceMode);
void GetAudio(void *Buf, int64_t Start, int64_t Count);
};
#endif // HAALISOURCE

View file

@ -21,21 +21,22 @@
#include <sstream>
#include <iomanip>
#include "ffms.h"
#include "ffvideosource.h"
#include "ffaudiosource.h"
#include "videosource.h"
#include "audiosource.h"
#include "indexing.h"
static bool FFmpegInited = false;
bool HasHaaliMPEG = false;
bool HasHaaliOGG = false;
int CPUFeatures = 0;
#ifdef FFMS_WIN_DEBUG
extern "C" int av_log_level;
void av_log_windebug_callback(void* ptr, int level, const char* fmt, va_list vl)
{
void av_log_windebug_callback(void* ptr, int level, const char* fmt, va_list vl) {
static int print_prefix=1;
static int count;
static char line[1024], prev[1024];
@ -56,7 +57,9 @@ void av_log_windebug_callback(void* ptr, int level, const char* fmt, va_list vl)
return;
}
if(count>0){
fprintf(stderr, " Last message repeated %d times\n", count);
std::stringstream ss;
ss << " Last message repeated " << count << " times\n";
OutputDebugStringA(ss.str().c_str());
count=0;
}
OutputDebugStringA(line);
@ -75,6 +78,13 @@ FFMS_API(void) FFMS_Init(int CPUFeatures) {
av_log_set_level(AV_LOG_QUIET);
#endif
::CPUFeatures = CPUFeatures;
#ifdef HAALISOURCE
CComPtr<IMMContainer> pMMC;
HasHaaliMPEG = !FAILED(pMMC.CoCreateInstance(HAALI_MPEG_PARSER));
pMMC = NULL;
HasHaaliOGG = !FAILED(pMMC.CoCreateInstance(HAALI_OGG_PARSER));
pMMC = NULL;
#endif
FFmpegInited = true;
}
}
@ -87,171 +97,224 @@ FFMS_API(void) FFMS_SetLogLevel(int Level) {
av_log_set_level(Level);
}
FFMS_API(FFVideo *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize) {
if (Track < 0 || Track >= static_cast<int>(Index->size())) {
snprintf(ErrorMsg, MsgSize, "Out of bounds track index selected");
return NULL;
}
if (Index->at(Track).TT != FFMS_TYPE_VIDEO) {
snprintf(ErrorMsg, MsgSize, "Not a video track");
return NULL;
}
FFMS_API(FFMS_VideoSource *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode, FFMS_ErrorInfo *ErrorInfo) {
try {
switch (Index->Decoder) {
case 0: return new FFLAVFVideo(SourceFile, Track, Index, PP, Threads, SeekMode, ErrorMsg, MsgSize);
case 1: return new FFMatroskaVideo(SourceFile, Track, Index, PP, Threads, ErrorMsg, MsgSize);
case FFMS_SOURCE_LAVF:
return new FFLAVFVideo(SourceFile, Track, Index, Threads, SeekMode);
case FFMS_SOURCE_MATROSKA:
return new FFMatroskaVideo(SourceFile, Track, Index, Threads);
#ifdef HAALISOURCE
case 2: return new FFHaaliVideo(SourceFile, Track, Index, PP, Threads, 0, ErrorMsg, MsgSize);
case 3: return new FFHaaliVideo(SourceFile, Track, Index, PP, Threads, 1, ErrorMsg, MsgSize);
case FFMS_SOURCE_HAALIMPEG:
if (HasHaaliMPEG)
return new FFHaaliVideo(SourceFile, Track, Index, Threads, FFMS_SOURCE_HAALIMPEG);
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali MPEG/TS source unavailable");
case FFMS_SOURCE_HAALIOGG:
if (HasHaaliOGG)
return new FFHaaliVideo(SourceFile, Track, Index, Threads, FFMS_SOURCE_HAALIOGG);
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali OGG/OGM source unavailable");
#endif
default:
snprintf(ErrorMsg, MsgSize, "Unsupported format");
return NULL;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Unsupported format");
}
} catch (...) {
} catch (FFMS_Exception &e) {
e.CopyOut(ErrorInfo);
return NULL;
}
}
FFMS_API(FFAudio *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize) {
if (Track < 0 || Track >= static_cast<int>(Index->size())) {
snprintf(ErrorMsg, MsgSize, "Out of bounds track index selected");
return NULL;
}
if (Index->at(Track).TT != FFMS_TYPE_AUDIO) {
snprintf(ErrorMsg, MsgSize, "Not an audio track");
return NULL;
}
FFMS_API(FFMS_AudioSource *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo) {
try {
switch (Index->Decoder) {
case 0: return new FFLAVFAudio(SourceFile, Track, Index, ErrorMsg, MsgSize);
case 1: return new FFMatroskaAudio(SourceFile, Track, Index, ErrorMsg, MsgSize);
case FFMS_SOURCE_LAVF:
return new FFLAVFAudio(SourceFile, Track, Index);
case FFMS_SOURCE_MATROSKA:
return new FFMatroskaAudio(SourceFile, Track, Index);
#ifdef HAALISOURCE
case 2: return new FFHaaliAudio(SourceFile, Track, Index, 0, ErrorMsg, MsgSize);
case 3: return new FFHaaliAudio(SourceFile, Track, Index, 1, ErrorMsg, MsgSize);
case FFMS_SOURCE_HAALIMPEG:
if (HasHaaliMPEG)
return new FFHaaliAudio(SourceFile, Track, Index, FFMS_SOURCE_HAALIMPEG);
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);
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_NOT_AVAILABLE, "Haali OGG/OGM source unavailable");
#endif
default:
snprintf(ErrorMsg, MsgSize, "Unsupported format");
return NULL;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, "Unsupported format");
}
} catch (...) {
} catch (FFMS_Exception &e) {
e.CopyOut(ErrorInfo);
return NULL;
}
}
FFMS_API(void) FFMS_DestroyVideoSource(FFVideo *V) {
FFMS_API(void) FFMS_DestroyVideoSource(FFMS_VideoSource *V) {
delete V;
}
FFMS_API(void) FFMS_DestroyAudioSource(FFAudio *A) {
FFMS_API(void) FFMS_DestroyAudioSource(FFMS_AudioSource *A) {
delete A;
}
FFMS_API(const FFVideoProperties *) FFMS_GetVideoProperties(FFVideo *V) {
return &V->GetFFVideoProperties();
FFMS_API(const FFMS_VideoProperties *) FFMS_GetVideoProperties(FFMS_VideoSource *V) {
return &V->GetVideoProperties();
}
FFMS_API(const FFAudioProperties *) FFMS_GetAudioProperties(FFAudio *A) {
return &A->GetFFAudioProperties();
FFMS_API(const FFMS_AudioProperties *) FFMS_GetAudioProperties(FFMS_AudioSource *A) {
return &A->GetAudioProperties();
}
FFMS_API(const FFAVFrame *) FFMS_GetFrame(FFVideo *V, int n, char *ErrorMsg, unsigned MsgSize) {
return (FFAVFrame *)V->GetFrame(n, ErrorMsg, MsgSize);
FFMS_API(const FFMS_Frame *) FFMS_GetFrame(FFMS_VideoSource *V, int n, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
return V->GetFrame(n);
} catch (FFMS_Exception &e) {
e.CopyOut(ErrorInfo);
return NULL;
}
}
FFMS_API(const FFAVFrame *) FFMS_GetFrameByTime(FFVideo *V, double Time, char *ErrorMsg, unsigned MsgSize) {
return (FFAVFrame *)V->GetFrameByTime(Time, ErrorMsg, MsgSize);
FFMS_API(const FFMS_Frame *) FFMS_GetFrameByTime(FFMS_VideoSource *V, double Time, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
return (FFMS_Frame *)V->GetFrameByTime(Time);
} catch (FFMS_Exception &e) {
e.CopyOut(ErrorInfo);
return NULL;
}
}
FFMS_API(int) FFMS_GetAudio(FFAudio *A, void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize) {
return A->GetAudio(Buf, Start, Count, ErrorMsg, MsgSize);
FFMS_API(int) FFMS_GetAudio(FFMS_AudioSource *A, void *Buf, int64_t Start, int64_t Count, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
A->GetAudio(Buf, Start, Count);
} catch (FFMS_Exception &e) {
return e.CopyOut(ErrorInfo);
}
return FFMS_ERROR_SUCCESS;
}
FFMS_API(int) FFMS_SetOutputFormatV(FFVideo *V, int64_t TargetFormats, int Width, int Height, int Resizer, char *ErrorMsg, unsigned MsgSize) {
return V->SetOutputFormat(TargetFormats, Width, Height, Resizer, ErrorMsg, MsgSize);
FFMS_API(int) FFMS_SetOutputFormatV(FFMS_VideoSource *V, int64_t TargetFormats, int Width, int Height, int Resizer, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
V->SetOutputFormat(TargetFormats, Width, Height, Resizer);
} catch (FFMS_Exception &e) {
return e.CopyOut(ErrorInfo);
}
return FFMS_ERROR_SUCCESS;
}
FFMS_API(void) FFMS_ResetOutputFormatV(FFVideo *V) {
FFMS_API(void) FFMS_ResetOutputFormatV(FFMS_VideoSource *V) {
V->ResetOutputFormat();
}
FFMS_API(void) FFMS_DestroyIndex(FFIndex *Index) {
FFMS_API(int) FFMS_SetPP(FFMS_VideoSource *V, const char *PP, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
V->SetPP(PP);
} catch (FFMS_Exception &e) {
return e.CopyOut(ErrorInfo);
}
return FFMS_ERROR_SUCCESS;
}
FFMS_API(void) FFMS_ResetPP(FFMS_VideoSource *V) {
V->ResetPP();
}
FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index) {
delete Index;
}
FFMS_API(int) FFMS_GetFirstTrackOfType(FFIndex *Index, int TrackType, char *ErrorMsg, unsigned MsgSize) {
FFMS_API(int) FFMS_GetFirstTrackOfType(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)
return i;
snprintf(ErrorMsg, MsgSize, "No suitable, indexed track found");
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;
}
}
FFMS_API(int) FFMS_GetFirstIndexedTrackOfType(FFIndex *Index, int TrackType, char *ErrorMsg, unsigned MsgSize) {
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].size() > 0)
return i;
snprintf(ErrorMsg, MsgSize, "No suitable, indexed track found");
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;
}
}
FFMS_API(int) FFMS_GetNumTracks(FFIndex *Index) {
FFMS_API(int) FFMS_GetNumTracks(FFMS_Index *Index) {
return Index->size();
}
FFMS_API(int) FFMS_GetNumTracksI(FFIndexer *Indexer) {
FFMS_API(int) FFMS_GetNumTracksI(FFMS_Indexer *Indexer) {
return Indexer->GetNumberOfTracks();
}
FFMS_API(int) FFMS_GetTrackType(FFTrack *T) {
FFMS_API(int) FFMS_GetTrackType(FFMS_Track *T) {
return T->TT;
}
FFMS_API(int) FFMS_GetTrackTypeI(FFIndexer *Indexer, int Track) {
FFMS_API(int) FFMS_GetTrackTypeI(FFMS_Indexer *Indexer, int Track) {
return Indexer->GetTrackType(Track);
}
FFMS_API(const char *) FFMS_GetCodecNameI(FFIndexer *Indexer, int Track) {
FFMS_API(const char *) FFMS_GetCodecNameI(FFMS_Indexer *Indexer, int Track) {
return Indexer->GetTrackCodec(Track);
}
FFMS_API(int) FFMS_GetNumFrames(FFTrack *T) {
FFMS_API(int) FFMS_GetNumFrames(FFMS_Track *T) {
return T->size();
}
FFMS_API(const FFFrameInfo *) FFMS_GetFrameInfo(FFTrack *T, int Frame) {
return reinterpret_cast<FFFrameInfo *>(&(*T)[Frame]);
FFMS_API(const FFMS_FrameInfo *) FFMS_GetFrameInfo(FFMS_Track *T, int Frame) {
return reinterpret_cast<FFMS_FrameInfo *>(&(*T)[Frame]);
}
FFMS_API(FFTrack *) FFMS_GetTrackFromIndex(FFIndex *Index, int Track) {
FFMS_API(FFMS_Track *) FFMS_GetTrackFromIndex(FFMS_Index *Index, int Track) {
return &(*Index)[Track];
}
FFMS_API(FFTrack *) FFMS_GetTrackFromVideo(FFVideo *V) {
return V->GetFFTrack();
FFMS_API(FFMS_Track *) FFMS_GetTrackFromVideo(FFMS_VideoSource *V) {
return V->GetTrack();
}
FFMS_API(FFTrack *) FFMS_GetTrackFromAudio(FFAudio *A) {
return A->GetFFTrack();
FFMS_API(FFMS_Track *) FFMS_GetTrackFromAudio(FFMS_AudioSource *A) {
return A->GetTrack();
}
FFMS_API(const FFTrackTimeBase *) FFMS_GetTimeBase(FFTrack *T) {
FFMS_API(const FFMS_TrackTimeBase *) FFMS_GetTimeBase(FFMS_Track *T) {
return &T->TB;
}
FFMS_API(int) FFMS_WriteTimecodes(FFTrack *T, const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize) {
return T->WriteTimecodes(TimecodeFile, ErrorMsg, MsgSize);
FFMS_API(int) FFMS_WriteTimecodes(FFMS_Track *T, const char *TimecodeFile, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
T->WriteTimecodes(TimecodeFile);
} catch (FFMS_Exception &e) {
return e.CopyOut(ErrorInfo);
}
return FFMS_ERROR_SUCCESS;
}
FFMS_API(FFIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize) {
FFIndexer *Indexer = FFMS_CreateIndexer(SourceFile, ErrorMsg, MsgSize);
FFMS_API(FFMS_Index *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo) {
FFMS_Indexer *Indexer = FFMS_CreateIndexer(SourceFile, ErrorInfo);
if (!Indexer)
return NULL;
return FFMS_DoIndexing(Indexer, IndexMask, DumpMask, ANC, ANCPrivate, IgnoreDecodeErrors, IC, ICPrivate, ErrorMsg, MsgSize);
return FFMS_DoIndexing(Indexer, IndexMask, DumpMask, ANC, ANCPrivate, ErrorHandling, IC, ICPrivate, ErrorInfo);
}
/* Used by FFMS_DefaultAudioFilename */
@ -270,7 +333,7 @@ static void ReplaceString(std::string &s, std::string from, std::string to) {
s.replace(idx, from.length(), to);
}
FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const FFAudioProperties *AP, char *FileName, int FNSize, void *Private) {
FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const FFMS_AudioProperties *AP, char *FileName, int FNSize, void *Private) {
std::string s = static_cast<char *>(Private);
ReplaceString(s, "%sourcefile%", SourceFile);
@ -281,55 +344,99 @@ FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const
ReplaceString(s, "%bps%", IntToStr(AP->BitsPerSample));
ReplaceString(s, "%delay%", IntToStr(static_cast<int>(AP->FirstTime)));
if (FileName == NULL) {
return s.length() + 1;
} else {
if (FileName != NULL)
strcpy(FileName, s.c_str());
return 0;
}
return s.length() + 1;
}
FFMS_API(FFIndexer *) FFMS_CreateIndexer(const char *SourceFile, char *ErrorMsg, unsigned MsgSize) {
FFMS_API(FFMS_Indexer *) FFMS_CreateIndexer(const char *SourceFile, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
return FFIndexer::CreateFFIndexer(SourceFile, ErrorMsg, MsgSize);
} catch (...) {
return FFMS_Indexer::CreateIndexer(SourceFile);
} catch (FFMS_Exception &e) {
e.CopyOut(ErrorInfo);
return NULL;
}
}
FFMS_API(FFIndex *) FFMS_DoIndexing(FFIndexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize) {
FFMS_API(FFMS_Index *) FFMS_DoIndexing(FFMS_Indexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, int ErrorHandling, TIndexCallback IC, void *ICPrivate, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
Indexer->SetIndexMask(IndexMask | DumpMask);
Indexer->SetDumpMask(DumpMask);
Indexer->SetIgnoreDecodeErrors(IgnoreDecodeErrors);
Indexer->SetErrorHandling(ErrorHandling);
Indexer->SetProgressCallback(IC, ICPrivate);
Indexer->SetAudioNameCallback(ANC, ANCPrivate);
FFIndex *Index = Indexer->DoIndexing(ErrorMsg, MsgSize);
FFMS_Index *Index = NULL;
try {
Index = Indexer->DoIndexing();
} catch (FFMS_Exception &e) {
e.CopyOut(ErrorInfo);
}
delete Indexer;
return Index;
}
FFMS_API(void) FFMS_CancelIndexing(FFIndexer *Indexer) {
FFMS_API(void) FFMS_CancelIndexing(FFMS_Indexer *Indexer) {
delete Indexer;
}
FFMS_API(FFIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize) {
FFIndex *Index = new FFIndex();
if (Index->ReadIndex(IndexFile, ErrorMsg, MsgSize)) {
FFMS_API(FFMS_Index *) FFMS_ReadIndex(const char *IndexFile, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
FFMS_Index *Index = new FFMS_Index();
try {
Index->ReadIndex(IndexFile);
} catch (FFMS_Exception &e) {
delete Index;
e.CopyOut(ErrorInfo);
return NULL;
} else {
}
return Index;
}
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;
}
FFMS_API(int) FFMS_IndexBelongsToFile(FFIndex *Index, const char *SourceFile, char *ErrorMsg, unsigned MsgSize) {
return Index->CompareFileSignature(SourceFile, ErrorMsg, MsgSize);
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo) {
ClearErrorInfo(ErrorInfo);
try {
Index->WriteIndex(IndexFile);
} catch (FFMS_Exception &e) {
return e.CopyOut(ErrorInfo);
}
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFIndex *Index, char *ErrorMsg, unsigned MsgSize) {
return Index->WriteIndex(IndexFile, ErrorMsg, MsgSize);
return FFMS_ERROR_SUCCESS;
}
FFMS_API(int) FFMS_GetPixFmt(const char *Name) {
return avcodec_get_pix_fmt(Name);
}
FFMS_API(int) FFMS_GetPresentSources() {
int Sources = FFMS_SOURCE_LAVF | FFMS_SOURCE_MATROSKA;
#ifdef HAALISOURCE
Sources |= FFMS_SOURCE_HAALIMPEG | FFMS_SOURCE_HAALIOGG;
#endif
return Sources;
}
FFMS_API(int) FFMS_GetEnabledSources() {
if (!FFmpegInited)
return 0;
int Sources = FFMS_SOURCE_LAVF | FFMS_SOURCE_MATROSKA;
if (HasHaaliMPEG)
Sources |= FFMS_SOURCE_HAALIMPEG;
if (HasHaaliOGG)
Sources |= FFMS_SOURCE_HAALIOGG;
return Sources;
}

View file

@ -116,10 +116,10 @@ DEFINE_GUID(MEDIASUBTYPE_WMV3,
0x33564d57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
// FIXME: move somewhere else?
DEFINE_GUID(HAALI_TS_Parser,
DEFINE_GUID(HAALI_MPEG_PARSER,
0xB841F346, 0x4835, 0x4de8, 0xAA, 0x5E, 0x2E, 0x7C, 0xD2, 0xD4, 0xC4, 0x35);
DEFINE_GUID(HAALI_OGM_Parser,
DEFINE_GUID(HAALI_OGG_PARSER,
0xDB43B405, 0x43AA, 0x4F01, 0x82, 0xD8, 0xD8, 0x4D, 0x47, 0xE6, 0x01, 0x9C);
//DB43B405-43AA-4F01-82D8-D84D47E6019C

View file

@ -20,7 +20,9 @@
#ifdef HAALISOURCE
#include "ffaudiosource.h"
#include "audiosource.h"
void FFHaaliAudio::Free(bool CloseCodec) {
if (CloseCodec)
@ -28,14 +30,14 @@ void FFHaaliAudio::Free(bool CloseCodec) {
av_freep(&CodecContext);
}
int FFHaaliAudio::DecodeNextAudioBlock(int64_t *AFirstStartTime, int64_t *Count, char *ErrorMsg, unsigned MsgSize) {
void FFHaaliAudio::DecodeNextAudioBlock(int64_t *AFirstStartTime, int64_t *Count) {
const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8;
int Ret = -1;
*AFirstStartTime = -1;
*Count = 0;
uint8_t *Buf = &DecodingBuffer[0];
AVPacket Packet;
InitNullPacket(&Packet);
InitNullPacket(Packet);
for (;;) {
CComPtr<IMMFrame> pMMF;
@ -79,56 +81,17 @@ int FFHaaliAudio::DecodeNextAudioBlock(int64_t *AFirstStartTime, int64_t *Count,
}
}
Done:
return Ret;
Done:;
}
FFHaaliAudio::FFHaaliAudio(const char *SourceFile, int Track, FFIndex *Index,
int SourceMode, char *ErrorMsg, unsigned MsgSize)
: FFAudio(SourceFile, Index, ErrorMsg, MsgSize) {
FFHaaliAudio::FFHaaliAudio(const char *SourceFile, int Track, FFMS_Index *Index, enum FFMS_Sources SourceMode)
: Res(FFSourceResources<FFMS_AudioSource>(this)), FFMS_AudioSource(SourceFile, Index, Track) {
AVCodec *Codec = NULL;
CodecContext = NULL;
AudioTrack = Track;
Frames = (*Index)[AudioTrack];
if (Frames.size() == 0) {
snprintf(ErrorMsg, MsgSize, "Audio track contains no frames, was it indexed properly?");
throw ErrorMsg;
}
CLSID clsid = HAALI_TS_Parser;
if (SourceMode == 1)
clsid = HAALI_OGM_Parser;
if (FAILED(pMMC.CoCreateInstance(clsid))) {
snprintf(ErrorMsg, MsgSize, "Can't create parser");
throw ErrorMsg;
}
CComPtr<IMemAlloc> pMA;
if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc))) {
snprintf(ErrorMsg, MsgSize, "Can't create memory allocator");
throw ErrorMsg;
}
CComPtr<IMMStream> pMS;
if (FAILED(pMS.CoCreateInstance(CLSID_DiskFile))) {
snprintf(ErrorMsg, MsgSize, "Can't create disk file reader");
throw ErrorMsg;
}
WCHAR WSourceFile[2048];
ffms_mbstowcs(WSourceFile, SourceFile, 2000);
CComQIPtr<IMMStreamOpen> pMSO(pMS);
if (FAILED(pMSO->Open(WSourceFile))) {
snprintf(ErrorMsg, MsgSize, "Can't open file");
throw ErrorMsg;
}
if (FAILED(pMMC->Open(pMS, 0, NULL, pMA))) {
snprintf(ErrorMsg, MsgSize, "Can't parse file");
throw ErrorMsg;
}
pMMC = HaaliOpenFile(SourceFile, SourceMode);
int CodecPrivateSize = 0;
int CurrentTrack = 0;
@ -154,7 +117,13 @@ FFHaaliAudio::FFHaaliAudio(const char *SourceFile, int Track, FFIndex *Index,
if (SUCCEEDED(pBag->Read(L"CodecID", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_BSTR))) {
char ACodecID[2048];
wcstombs(ACodecID, pV.bstrVal, 2000);
Codec = avcodec_find_decoder(MatroskaToFFCodecID(ACodecID, FFMS_GET_VECTOR_PTR(CodecPrivate)));
int BitDepth = 0;
pV.Clear();
if (SUCCEEDED(pBag->Read(L"Audio.BitDepth", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
BitDepth = pV.uintVal;
Codec = avcodec_find_decoder(MatroskaToFFCodecID(ACodecID, FFMS_GET_VECTOR_PTR(CodecPrivate), 0, BitDepth));
}
}
}
@ -166,45 +135,37 @@ FFHaaliAudio::FFHaaliAudio(const char *SourceFile, int Track, FFIndex *Index,
CodecContext->extradata = FFMS_GET_VECTOR_PTR(CodecPrivate);
CodecContext->extradata_size = CodecPrivateSize;
if (Codec == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Audio codec not found");
throw ErrorMsg;
}
if (Codec == NULL)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Audio codec not found");
InitializeCodecContextFromHaaliInfo(pBag, CodecContext);
if (avcodec_open(CodecContext, Codec) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
throw ErrorMsg;
}
if (avcodec_open(CodecContext, Codec) < 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Could not open audio codec");
Res.CloseCodec(true);
// Always try to decode a frame to make sure all required parameters are known
int64_t Dummy1, Dummy2;
if (DecodeNextAudioBlock(&Dummy1, &Dummy2, ErrorMsg, MsgSize) < 0) {
Free(true);
throw ErrorMsg;
}
DecodeNextAudioBlock(&Dummy1, &Dummy2);
pMMC->Seek(Frames[0].DTS, MKVF_SEEK_TO_PREV_KEYFRAME_STRICT);
avcodec_flush_buffers(CodecContext);
FillAP(AP, CodecContext, Frames);
if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0) {
Free(true);
snprintf(ErrorMsg, MsgSize, "Codec returned zero size audio");
throw ErrorMsg;
}
if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Codec returned zero size audio");
AudioCache.Initialize((AP.Channels * AP.BitsPerSample) / 8, 50);
}
FFHaaliAudio::~FFHaaliAudio() {
Free(true);
}
void FFHaaliAudio::GetAudio(void *Buf, int64_t Start, int64_t Count) {
GetAudioCheck(Start, Count);
int FFHaaliAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize) {
const int64_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8;
memset(Buf, 0, static_cast<size_t>(SizeConst * Count));
bool HasSeeked = false;
@ -216,7 +177,7 @@ int FFHaaliAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorM
int64_t CacheEnd = AudioCache.FillRequest(Start, Count, DstBuf);
// Was everything in the cache?
if (CacheEnd == Start + Count)
return 0;
return;
int CurrentAudioBlock;
// Is seeking required to decode the requested samples?
@ -234,11 +195,7 @@ int FFHaaliAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorM
int64_t FirstTime, DecodeCount;
do {
int Ret = DecodeNextAudioBlock(&FirstTime, &DecodeCount, ErrorMsg, MsgSize);
if (Ret < 0) {
// FIXME
//Env->ThrowError("Bleh, bad audio decoding");
}
DecodeNextAudioBlock(&FirstTime, &DecodeCount);
if (HasSeeked) {
CurrentAudioBlock = Frames.ClosestFrameFromDTS(FirstTime);
@ -257,8 +214,6 @@ int FFHaaliAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorM
if (CurrentAudioBlock < static_cast<int>(Frames.size()))
CurrentSample = Frames[CurrentAudioBlock].SampleStart;
} while (Start + Count - CacheEnd > 0 && CurrentAudioBlock < static_cast<int>(Frames.size()));
return 0;
}
#endif // HAALISOURCE

View file

@ -24,51 +24,17 @@
FFHaaliIndexer::FFHaaliIndexer(const char *Filename, int SourceMode, char *ErrorMsg, unsigned MsgSize) : FFIndexer(Filename, ErrorMsg, MsgSize) {
SourceFile = Filename;
FFHaaliIndexer::FFHaaliIndexer(const char *Filename, enum FFMS_Sources SourceMode) : FFMS_Indexer(Filename) {
this->SourceMode = SourceMode;
memset(TrackType, FFMS_TYPE_UNKNOWN, sizeof(TrackType));
memset(Codec, 0, sizeof(Codec));
memset(CodecPrivate, 0, sizeof(CodecPrivate));
memset(CodecPrivateSize, 0, sizeof(CodecPrivateSize));
SourceFile = Filename;
Duration = 0;
CLSID clsid = HAALI_TS_Parser;
if (SourceMode == 1)
clsid = HAALI_OGM_Parser;
if (FAILED(pMMC.CoCreateInstance(clsid))) {
snprintf(ErrorMsg, MsgSize, "Can't create parser");
throw ErrorMsg;
for (int i = 0; i < 32; i++) {
TrackType[i] = FFMS_TYPE_UNKNOWN;
Codec[i] = NULL;
CodecPrivateSize[i] = 0;
}
CComPtr<IMemAlloc> pMA;
if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc))) {
snprintf(ErrorMsg, MsgSize, "Can't create memory allocator");
throw ErrorMsg;
}
CComPtr<IMMStream> pMS;
if (FAILED(pMS.CoCreateInstance(CLSID_DiskFile))) {
snprintf(ErrorMsg, MsgSize, "Can't create disk file reader");
throw ErrorMsg;
}
WCHAR WSourceFile[2048];
ffms_mbstowcs(WSourceFile, SourceFile, 2000);
CComQIPtr<IMMStreamOpen> pMSO(pMS);
if (FAILED(pMSO->Open(WSourceFile))) {
snprintf(ErrorMsg, MsgSize, "Can't open file");
throw ErrorMsg;
}
if (FAILED(pMMC->Open(pMS, 0, NULL, pMA))) {
if (SourceMode == 0)
snprintf(ErrorMsg, MsgSize, "Can't parse file, most likely a transport stream not cut at packet boundaries");
else if (SourceMode == 1)
snprintf(ErrorMsg, MsgSize, "Can't parse file");
throw ErrorMsg;
}
pMMC = HaaliOpenFile(SourceFile, SourceMode);
CComQIPtr<IPropertyBag> pBag2 = pMMC;
CComVariant pV2;
@ -99,14 +65,42 @@ FFHaaliIndexer::FFHaaliIndexer(const char *Filename, int SourceMode, char *Error
}
pV.Clear();
if (SUCCEEDED(pBag->Read(L"FOURCC", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
if (SUCCEEDED(pBag->Read(L"FOURCC", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4))) {
FourCC = pV.uintVal;
// Reconstruct the missing codec private part for VC1
std::vector<uint8_t> bihvect;
bihvect.resize(sizeof(FFMS_BITMAPINFOHEADER));
FFMS_BITMAPINFOHEADER *bih = reinterpret_cast<FFMS_BITMAPINFOHEADER *>(FFMS_GET_VECTOR_PTR(bihvect));
memset(bih, 0, sizeof(FFMS_BITMAPINFOHEADER));
bih->biSize = sizeof(FFMS_BITMAPINFOHEADER) + CodecPrivateSize[NumTracks];
bih->biCompression = FourCC;
bih->biBitCount = 24;
bih->biPlanes = 1;
pV.Clear();
if (SUCCEEDED(pBag->Read(L"Video.PixelWidth", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
bih->biWidth = pV.uintVal;
pV.Clear();
if (SUCCEEDED(pBag->Read(L"Video.PixelHeight", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
bih->biHeight = pV.uintVal;
CodecPrivate[NumTracks].insert(CodecPrivate[NumTracks].begin(), bihvect.begin(), bihvect.end());
CodecPrivateSize[NumTracks] += sizeof(FFMS_BITMAPINFOHEADER);
}
pV.Clear();
if (SUCCEEDED(pBag->Read(L"CodecID", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_BSTR))) {
char CodecID[2048];
wcstombs(CodecID, pV.bstrVal, 2000);
Codec[NumTracks] = avcodec_find_decoder(MatroskaToFFCodecID(CodecID, FFMS_GET_VECTOR_PTR(CodecPrivate[NumTracks]), FourCC));
char CodecStr[2048];
wcstombs(CodecStr, pV.bstrVal, 2000);
int BitDepth = 0;
pV.Clear();
if (SUCCEEDED(pBag->Read(L"Audio.BitDepth", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
BitDepth = pV.uintVal;
Codec[NumTracks] = avcodec_find_decoder(MatroskaToFFCodecID(CodecStr, FFMS_GET_VECTOR_PTR(CodecPrivate[NumTracks]), FourCC, BitDepth));
}
}
@ -116,17 +110,17 @@ FFHaaliIndexer::FFHaaliIndexer(const char *Filename, int SourceMode, char *Error
}
}
FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
FFMS_Index *FFHaaliIndexer::DoIndexing() {
std::vector<SharedAudioContext> AudioContexts(NumTracks, SharedAudioContext(true));
std::vector<SharedVideoContext> VideoContexts(NumTracks, SharedVideoContext(true));
std::auto_ptr<FFIndex> TrackIndices(new FFIndex(Filesize, Digest));
TrackIndices->Decoder = 2;
if (SourceMode == 1)
TrackIndices->Decoder = 3;
std::auto_ptr<FFMS_Index> TrackIndices(new FFMS_Index(Filesize, Digest));
TrackIndices->Decoder = FFMS_SOURCE_HAALIMPEG;
if (SourceMode == FFMS_SOURCE_HAALIOGG)
TrackIndices->Decoder = FFMS_SOURCE_HAALIOGG;
for (int i = 0; i < NumTracks; i++) {
TrackIndices->push_back(FFTrack(1, 1000000, TrackType[i]));
TrackIndices->push_back(FFMS_Track(1, 1000000, TrackType[i]));
if (TrackType[i] == FFMS_TYPE_VIDEO && Codec[i] && (VideoContexts[i].Parser = av_parser_init(Codec[i]->id))) {
@ -138,8 +132,8 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
if (avcodec_open(CodecContext, Codec[i]) < 0) {
av_freep(&CodecContext);
snprintf(ErrorMsg, MsgSize, "Could not open video codec");
return NULL;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Could not open video codec");
}
VideoContexts[i].CodecContext = CodecContext;
@ -147,10 +141,9 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
}
if (IndexMask & (1 << i) && TrackType[i] == FFMS_TYPE_AUDIO) {
if (Codec[i] == NULL) {
snprintf(ErrorMsg, MsgSize, "Audio codec not found");
return NULL;
}
if (Codec[i] == NULL)
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
"Audio codec not found");
AVCodecContext *CodecContext = avcodec_alloc_context();
CodecContext->extradata = FFMS_GET_VECTOR_PTR(CodecPrivate[i]);
@ -160,8 +153,8 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
if (avcodec_open(CodecContext, Codec[i]) < 0) {
av_freep(&CodecContext);
AudioContexts[i].CodecContext = NULL;
snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
return NULL;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Could not open audio codec");
}
} else {
IndexMask &= ~(1 << i);
@ -170,7 +163,7 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
//
AVPacket TempPacket;
InitNullPacket(&TempPacket);
InitNullPacket(TempPacket);
for (;;) {
CComPtr<IMMFrame> pMMF;
@ -183,16 +176,14 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
if (IC) {
if (Duration > 0) {
if (SUCCEEDED(hr)) {
if ((*IC)(Ts, Duration, ICPrivate)) {
snprintf(ErrorMsg, MsgSize, "Cancelled by user");
return NULL;
}
if ((*IC)(Ts, Duration, ICPrivate))
throw FFMS_Exception(FFMS_ERROR_CANCELLED, FFMS_ERROR_USER,
"Cancelled by user");
}
} else {
if ((*IC)(0, 1, ICPrivate)) {
snprintf(ErrorMsg, MsgSize, "Cancelled by user");
return NULL;
}
if ((*IC)(0, 1, ICPrivate))
throw FFMS_Exception(FFMS_ERROR_CANCELLED, FFMS_ERROR_USER,
"Cancelled by user");
}
}
@ -213,7 +204,7 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
(*TrackIndices)[Track].push_back(TFrameInfo::VideoFrameInfo(Ts, RepeatPict, pMMF->IsSyncPoint() == S_OK));
} else if (TrackType[Track] == FFMS_TYPE_AUDIO && (IndexMask & (1 << Track))) {
(*TrackIndices)[Track].push_back(TFrameInfo::AudioFrameInfo(Ts, AudioContexts[Track].CurrentSample, pMMF->IsSyncPoint() == S_OK));
int64_t StartSample = AudioContexts[Track].CurrentSample;
AVCodecContext *AudioCodecContext = AudioContexts[Track].CodecContext;
if (pMMF->IsSyncPoint() == S_OK)
@ -225,13 +216,18 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10;
int Ret = avcodec_decode_audio3(AudioCodecContext, &DecodingBuffer[0], &dbsize, &TempPacket);
if (Ret < 0) {
if (IgnoreDecodeErrors) {
if (ErrorHandling == FFMS_IEH_ABORT) {
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Audio decoding error");
} else if (ErrorHandling == FFMS_IEH_CLEAR_TRACK) {
(*TrackIndices)[Track].clear();
IndexMask &= ~(1 << Track);
break;
} else {
snprintf(ErrorMsg, MsgSize, "Audio decoding error");
return NULL;
} else if (ErrorHandling == FFMS_IEH_STOP_TRACK) {
IndexMask &= ~(1 << Track);
break;
} else if (ErrorHandling == FFMS_IEH_IGNORE) {
break;
}
}
@ -244,8 +240,11 @@ FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
AudioContexts[Track].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels);
if (DumpMask & (1 << Track))
WriteAudio(AudioContexts[Track], TrackIndices.get(), Track, dbsize, ErrorMsg, MsgSize);
WriteAudio(AudioContexts[Track], TrackIndices.get(), Track, dbsize);
}
(*TrackIndices)[Track].push_back(TFrameInfo::AudioFrameInfo(Ts, StartSample,
static_cast<unsigned int>(AudioContexts[Track].CurrentSample - StartSample), pMMF->IsSyncPoint() == S_OK));
}
}
@ -263,7 +262,7 @@ FFMS_TrackType FFHaaliIndexer::GetTrackType(int Track) {
const char *FFHaaliIndexer::GetTrackCodec(int Track) {
if (Codec[Track])
return Codec[Track]->long_name;
return Codec[Track]->name;
else
return "Unsupported codec/Unknown codec name";
}

View file

@ -18,10 +18,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffvideosource.h"
#ifdef HAALISOURCE
#include "videosource.h"
void FFHaaliVideo::Free(bool CloseCodec) {
if (CloseCodec)
avcodec_close(CodecContext);
@ -31,9 +33,8 @@ void FFHaaliVideo::Free(bool CloseCodec) {
}
FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track,
FFIndex *Index, const char *PP,
int Threads, int SourceMode, char *ErrorMsg, unsigned MsgSize)
: FFVideo(SourceFile, Index, ErrorMsg, MsgSize) {
FFMS_Index *Index, int Threads, enum FFMS_Sources SourceMode)
: Res(FFSourceResources<FFMS_VideoSource>(this)), FFMS_VideoSource(SourceFile, Index, Track) {
BitStreamFilter = NULL;
AVCodec *Codec = NULL;
@ -41,44 +42,7 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track,
VideoTrack = Track;
Frames = (*Index)[VideoTrack];
if (Frames.size() == 0) {
snprintf(ErrorMsg, MsgSize, "Video track contains no frames");
throw ErrorMsg;
}
CLSID clsid = HAALI_TS_Parser;
if (SourceMode == 1)
clsid = HAALI_OGM_Parser;
if (FAILED(pMMC.CoCreateInstance(clsid))) {
snprintf(ErrorMsg, MsgSize, "Can't create parser");
throw ErrorMsg;
}
CComPtr<IMemAlloc> pMA;
if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc))) {
snprintf(ErrorMsg, MsgSize, "Can't create memory allocator");
throw ErrorMsg;
}
CComPtr<IMMStream> pMS;
if (FAILED(pMS.CoCreateInstance(CLSID_DiskFile))) {
snprintf(ErrorMsg, MsgSize, "Can't create disk file reader");
throw ErrorMsg;
}
WCHAR WSourceFile[2048];
ffms_mbstowcs(WSourceFile, SourceFile, 2000);
CComQIPtr<IMMStreamOpen> pMSO(pMS);
if (FAILED(pMSO->Open(WSourceFile))) {
snprintf(ErrorMsg, MsgSize, "Can't open file");
throw ErrorMsg;
}
if (FAILED(pMMC->Open(pMS, 0, NULL, pMA))) {
snprintf(ErrorMsg, MsgSize, "Can't parse file");
throw ErrorMsg;
}
pMMC = HaaliOpenFile(SourceFile, SourceMode);
int CodecPrivateSize = 0;
int CurrentTrack = 0;
@ -102,9 +66,31 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track,
}
pV.Clear();
if (SUCCEEDED(pBag->Read(L"FOURCC", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
if (SUCCEEDED(pBag->Read(L"FOURCC", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4))) {
FourCC = pV.uintVal;
// Reconstruct the missing codec private part for VC1
std::vector<uint8_t> bihvect;
bihvect.resize(sizeof(FFMS_BITMAPINFOHEADER));
FFMS_BITMAPINFOHEADER *bih = reinterpret_cast<FFMS_BITMAPINFOHEADER *>(FFMS_GET_VECTOR_PTR(bihvect));
memset(bih, 0, sizeof(FFMS_BITMAPINFOHEADER));
bih->biSize = sizeof(FFMS_BITMAPINFOHEADER) + CodecPrivateSize;
bih->biCompression = FourCC;
bih->biBitCount = 24;
bih->biPlanes = 1;
pV.Clear();
if (SUCCEEDED(pBag->Read(L"Video.PixelWidth", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
bih->biWidth = pV.uintVal;
pV.Clear();
if (SUCCEEDED(pBag->Read(L"Video.PixelHeight", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4)))
bih->biHeight = pV.uintVal;
CodecPrivate.insert(CodecPrivate.begin(), bihvect.begin(), bihvect.end());
CodecPrivateSize += sizeof(FFMS_BITMAPINFOHEADER);
}
pV.Clear();
if (SUCCEEDED(pBag->Read(L"CodecID", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_BSTR))) {
char ACodecID[2048];
@ -122,51 +108,39 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track,
CodecContext->extradata_size = CodecPrivateSize;
CodecContext->thread_count = Threads;
if (Codec == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Video codec not found");
throw ErrorMsg;
}
if (Codec == NULL)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Video codec not found");
InitializeCodecContextFromHaaliInfo(pBag, CodecContext);
if (avcodec_open(CodecContext, Codec) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Could not open video codec");
throw ErrorMsg;
}
if (avcodec_open(CodecContext, Codec) < 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Could not open video codec");
if (Codec->id == CODEC_ID_H264 && SourceMode == 0)
if (Codec->id == CODEC_ID_H264 && SourceMode == FFMS_SOURCE_HAALIMPEG)
BitStreamFilter = av_bitstream_filter_init("h264_mp4toannexb");
Res.CloseCodec(true);
// Always try to decode a frame to make sure all required parameters are known
int64_t Dummy;
if (DecodeNextFrame(&Dummy, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
DecodeNextFrame(&Dummy);
VP.Width = CodecContext->width;
VP.Height = CodecContext->height;;
VP.FPSDenominator = 1;
VP.FPSNumerator = 30;
VP.RFFDenominator = CodecContext->time_base.num;
VP.RFFNumerator = CodecContext->time_base.den;
VP.NumFrames = Frames.size();
VP.VPixelFormat = CodecContext->pix_fmt;
VP.TopFieldFirst = DecodeFrame->top_field_first;
VP.ColorSpace = CodecContext->colorspace;
VP.ColorRange = CodecContext->color_range;
VP.FirstTime = ((Frames.front().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
VP.LastTime = ((Frames.back().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
if (VP.Width <= 0 || VP.Height <= 0) {
Free(true);
snprintf(ErrorMsg, MsgSize, "Codec returned zero size video");
throw ErrorMsg;
}
if (InitPP(PP, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
if (CodecContext->width <= 0 || CodecContext->height <= 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Codec returned zero size video");
// Calculate the average framerate
if (Frames.size() >= 2) {
@ -176,10 +150,7 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track,
}
// Output the already decoded frame so it isn't wasted
if (!OutputFrame(DecodeFrame, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
OutputFrame(DecodeFrame);
// Set AR variables
CComVariant pV;
@ -192,15 +163,11 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track,
VP.SARDen = pV.uiVal;
}
FFHaaliVideo::~FFHaaliVideo() {
Free(true);
}
int FFHaaliVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) {
void FFHaaliVideo::DecodeNextFrame(int64_t *AFirstStartTime) {
int FrameFinished = 0;
*AFirstStartTime = -1;
AVPacket Packet;
InitNullPacket(&Packet);
InitNullPacket(Packet);
for (;;) {
CComPtr<IMMFrame> pMMF;
@ -227,6 +194,9 @@ int FFHaaliVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsi
av_bitstream_filter_filter(BitStreamFilter, CodecContext, NULL,
&Packet.data, &Packet.size, Data, pMMF->GetActualDataLength(), !!Packet.flags);
if (CodecContext->codec_id == CODEC_ID_MPEG4 && IsNVOP(Packet))
goto Done;
avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet);
if (FrameFinished)
@ -237,7 +207,7 @@ int FFHaaliVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsi
// Flush the last frames
if (CodecContext->has_b_frames) {
AVPacket NullPacket;
InitNullPacket(&NullPacket);
InitNullPacket(NullPacket);
avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket);
}
@ -245,14 +215,14 @@ int FFHaaliVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsi
goto Error;
Error:
Done:
return 0;
Done:;
}
FFAVFrame *FFHaaliVideo::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) {
// PPFrame always holds frame LastFrameNum even if no PP is applied
FFMS_Frame *FFHaaliVideo::GetFrame(int n) {
GetFrameCheck(n);
if (LastFrameNum == n)
return OutputFrame(DecodeFrame, ErrorMsg, MsgSize);
return &LocalFrame;
bool HasSeeked = false;
int SeekOffset = 0;
@ -266,18 +236,16 @@ ReSeek:
do {
int64_t StartTime;
if (DecodeNextFrame(&StartTime, ErrorMsg, MsgSize))
return NULL;
DecodeNextFrame(&StartTime);
if (HasSeeked) {
HasSeeked = false;
if (StartTime < 0 || (CurrentFrame = Frames.FrameFromDTS(StartTime)) < 0) {
// No idea where we are so go back a bit further
if (n + SeekOffset == 0) {
snprintf(ErrorMsg, MsgSize, "Frame accurate seeking is not possible in this file\n");
return NULL;
}
if (n + SeekOffset == 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Frame accurate seeking is not possible in this file");
SeekOffset -= FFMIN(20, n + SeekOffset);
goto ReSeek;
@ -288,7 +256,7 @@ ReSeek:
} while (CurrentFrame <= n);
LastFrameNum = n;
return OutputFrame(DecodeFrame, ErrorMsg, MsgSize);
return OutputFrame(DecodeFrame);
}
#endif // HAALISOURCE

View file

@ -22,13 +22,15 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <stdio.h>
extern "C" {
#include <libavutil/sha1.h>
}
#define INDEXID 0x53920873
extern bool HasHaaliMPEG;
extern bool HasHaaliOGG;
struct IndexHeader {
uint32_t Id;
@ -44,6 +46,13 @@ struct IndexHeader {
uint8_t FileSignature[20];
};
struct TrackHeader {
uint32_t TT;
uint32_t Frames;
int64_t Num;
int64_t Den;
};
SharedVideoContext::SharedVideoContext(bool FreeCodecContext) {
CodecContext = NULL;
Parser = NULL;
@ -85,47 +94,49 @@ SharedAudioContext::~SharedAudioContext() {
cs_Destroy(CS);
}
TFrameInfo::TFrameInfo(int64_t DTS, int64_t SampleStart, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
TFrameInfo::TFrameInfo() {
}
TFrameInfo::TFrameInfo(int64_t DTS, int64_t SampleStart, unsigned int SampleCount, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
this->DTS = DTS;
this->RepeatPict = RepeatPict;
this->KeyFrame = KeyFrame;
this->SampleStart = SampleStart;
this->SampleCount = SampleCount;
this->FilePos = FilePos;
this->FrameSize = FrameSize;
this->OriginalPos = 0;
}
TFrameInfo TFrameInfo::VideoFrameInfo(int64_t DTS, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
return TFrameInfo(DTS, 0, RepeatPict, KeyFrame, FilePos, FrameSize);
return TFrameInfo(DTS, 0, 0, RepeatPict, KeyFrame, FilePos, FrameSize);
}
TFrameInfo TFrameInfo::AudioFrameInfo(int64_t DTS, int64_t SampleStart, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
return TFrameInfo(DTS, SampleStart, 0, KeyFrame, FilePos, FrameSize);
TFrameInfo TFrameInfo::AudioFrameInfo(int64_t DTS, int64_t SampleStart, unsigned int SampleCount, bool KeyFrame, int64_t FilePos, unsigned int FrameSize) {
return TFrameInfo(DTS, SampleStart, SampleCount, 0, KeyFrame, FilePos, FrameSize);
}
int FFTrack::WriteTimecodes(const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize) {
void FFMS_Track::WriteTimecodes(const char *TimecodeFile) {
ffms_fstream Timecodes(TimecodeFile, std::ios::out | std::ios::trunc);
if (!Timecodes.is_open()) {
snprintf(ErrorMsg, MsgSize, "Failed to open '%s' for writing", TimecodeFile);
return 1;
}
if (!Timecodes.is_open())
throw FFMS_Exception(FFMS_ERROR_TRACK, FFMS_ERROR_FILE_WRITE,
boost::format("Failed to open '%1%' for writing") % TimecodeFile);
Timecodes << "# timecode format v2\n";
for (iterator Cur=begin(); Cur!=end(); Cur++)
Timecodes << std::fixed << ((Cur->DTS * TB.Num) / (double)TB.Den) << "\n";
return 0;
}
int FFTrack::FrameFromDTS(int64_t DTS) {
int FFMS_Track::FrameFromDTS(int64_t DTS) {
for (int i = 0; i < static_cast<int>(size()); i++)
if (at(i).DTS == DTS)
return i;
return -1;
}
int FFTrack::ClosestFrameFromDTS(int64_t DTS) {
int FFMS_Track::ClosestFrameFromDTS(int64_t DTS) {
int Frame = 0;
int64_t BestDiff = 0xFFFFFFFFFFFFFFLL; // big number
for (int i = 0; i < static_cast<int>(size()); i++) {
@ -139,7 +150,7 @@ int FFTrack::ClosestFrameFromDTS(int64_t DTS) {
return Frame;
}
int FFTrack::FindClosestVideoKeyFrame(int Frame) {
int FFMS_Track::FindClosestVideoKeyFrame(int Frame) {
Frame = FFMIN(FFMAX(Frame, 0), static_cast<int>(size()) - 1);
for (int i = Frame; i > 0; i--)
if (at(i).KeyFrame)
@ -147,7 +158,7 @@ int FFTrack::FindClosestVideoKeyFrame(int Frame) {
return 0;
}
int FFTrack::FindClosestAudioKeyFrame(int64_t Sample) {
int FFMS_Track::FindClosestAudioKeyFrame(int64_t Sample) {
for (size_t i = 0; i < size(); i++) {
if (at(i).SampleStart == Sample && at(i).KeyFrame)
return i;
@ -157,29 +168,26 @@ int FFTrack::FindClosestAudioKeyFrame(int64_t Sample) {
return size() - 1;
}
FFTrack::FFTrack() {
FFMS_Track::FFMS_Track() {
this->TT = FFMS_TYPE_UNKNOWN;
this->TB.Num = 0;
this->TB.Den = 0;
}
FFTrack::FFTrack(int64_t Num, int64_t Den, FFMS_TrackType TT) {
FFMS_Track::FFMS_Track(int64_t Num, int64_t Den, FFMS_TrackType TT) {
this->TT = TT;
this->TB.Num = Num;
this->TB.Den = Den;
}
int FFIndex::CalculateFileSignature(const char *Filename, int64_t *Filesize, uint8_t Digest[20], char *ErrorMsg, unsigned MsgSize) {
// use cstdio because Microsoft's implementation of std::fstream doesn't support files >4GB.
// please kill me now.
void FFMS_Index::CalculateFileSignature(const char *Filename, int64_t *Filesize, uint8_t Digest[20]) {
FILE *SFile = ffms_fopen(Filename,"rb");
if (SFile == NULL) {
snprintf(ErrorMsg, MsgSize, "Failed to open '%s' for hashing", Filename);
return 1;
}
if (SFile == NULL)
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_READ,
boost::format("Failed to open '%1%' for hashing") % Filename);
const int BlockSize = 2*1024*1024;
const int BlockSize = 1024*1024;
std::vector<uint8_t> FileBuffer(BlockSize);
std::vector<uint8_t> ctxmem(av_sha1_size);
AVSHA1 *ctx = (AVSHA1 *)&ctxmem[0];
@ -188,10 +196,10 @@ int FFIndex::CalculateFileSignature(const char *Filename, int64_t *Filesize, uin
memset(&FileBuffer[0], 0, BlockSize);
fread(&FileBuffer[0], 1, BlockSize, SFile);
if (ferror(SFile) && !feof(SFile)) {
snprintf(ErrorMsg, MsgSize, "Failed to read from '%s' for hashing", Filename);
av_sha1_final(ctx, Digest);
fclose(SFile);
return 1;
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_READ,
boost::format("Failed to read '%1%' for hashing") % Filename);
}
av_sha1_update(ctx, &FileBuffer[0], BlockSize);
@ -199,61 +207,67 @@ int FFIndex::CalculateFileSignature(const char *Filename, int64_t *Filesize, uin
memset(&FileBuffer[0], 0, BlockSize);
fread(&FileBuffer[0], 1, BlockSize, SFile);
if (ferror(SFile) && !feof(SFile)) {
snprintf(ErrorMsg, MsgSize, "Failed to seek with offset %d from file end in '%s' for hashing", BlockSize, Filename);
av_sha1_final(ctx, Digest);
fclose(SFile);
return 1;
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_READ,
boost::format("Failed to seek with offset %1% from file end in '%2%' for hashing") % BlockSize % Filename);
}
av_sha1_update(ctx, &FileBuffer[0], BlockSize);
fseeko(SFile, 0, SEEK_END);
if (ferror(SFile)) {
snprintf(ErrorMsg, MsgSize, "Failed to seek to end of '%s' for hashing", Filename);
av_sha1_final(ctx, Digest);
fclose(SFile);
return 1;
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_READ,
boost::format("Failed to seek to end of '%1%' for hashing") % Filename);
}
*Filesize = ftello(SFile);
fclose(SFile);
av_sha1_final(ctx, Digest);
return 0;
}
static bool DTSComparison(TFrameInfo FI1, TFrameInfo FI2) {
return FI1.DTS < FI2.DTS;
}
void FFIndex::Sort() {
for (FFIndex::iterator Cur=begin(); Cur!=end(); Cur++)
void FFMS_Index::Sort() {
for (FFMS_Index::iterator Cur=begin(); Cur!=end(); Cur++) {
for (size_t i = 0; i < Cur->size(); i++)
Cur->at(i).OriginalPos = i;
std::sort(Cur->begin(), Cur->end(), DTSComparison);
std::vector<size_t> ReorderTemp;
ReorderTemp.resize(Cur->size());
for (size_t i = 0; i < Cur->size(); i++)
ReorderTemp[i] = Cur->at(i).OriginalPos;
for (size_t i = 0; i < Cur->size(); i++)
Cur->at(ReorderTemp[i]).OriginalPos = i;
}
}
int FFIndex::CompareFileSignature(const char *Filename, char *ErrorMsg, unsigned MsgSize) {
bool FFMS_Index::CompareFileSignature(const char *Filename) {
int64_t CFilesize;
uint8_t CDigest[20];
CalculateFileSignature(Filename, &CFilesize, CDigest, ErrorMsg, MsgSize);
if (CFilesize != Filesize || memcmp(CDigest, Digest, sizeof(Digest))) {
snprintf(ErrorMsg, MsgSize, "Index and source file signature mismatch");
return 1;
CalculateFileSignature(Filename, &CFilesize, CDigest);
return (CFilesize == Filesize && !memcmp(CDigest, Digest, sizeof(Digest)));
}
return 0;
}
int FFIndex::WriteIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize) {
void FFMS_Index::WriteIndex(const char *IndexFile) {
ffms_fstream IndexStream(IndexFile, std::ios::out | std::ios::binary | std::ios::trunc);
if (!IndexStream.is_open()) {
snprintf(ErrorMsg, MsgSize, "Failed to open '%s' for writing", IndexFile);
return 1;
}
if (!IndexStream.is_open())
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_WRITE,
boost::format("Failed to open '%1%' for writing") % IndexFile);
// Write the index file header
IndexHeader IH;
IH.Id = INDEXID;
IH.Version = INDEXVERSION;
IH.Version = FFMS_VERSION;
IH.Tracks = size();
IH.Decoder = Decoder;
IH.LAVUVersion = avutil_version();
@ -267,158 +281,152 @@ int FFIndex::WriteIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize)
IndexStream.write(reinterpret_cast<char *>(&IH), sizeof(IH));
for (unsigned int i = 0; i < IH.Tracks; i++) {
uint32_t TT = at(i).TT;
IndexStream.write(reinterpret_cast<char *>(&TT), sizeof(TT));
int64_t Num = at(i).TB.Num;
IndexStream.write(reinterpret_cast<char *>(&Num), sizeof(Num));
int64_t Den = at(i).TB.Den;
IndexStream.write(reinterpret_cast<char *>(&Den), sizeof(Den));
int64_t Frames = at(i).size();
IndexStream.write(reinterpret_cast<char *>(&Frames), sizeof(Frames));
TrackHeader TH;
TH.TT = at(i).TT;
TH.Frames = at(i).size();
TH.Num = at(i).TB.Num;;
TH.Den = at(i).TB.Den;
for (FFTrack::iterator Cur=at(i).begin(); Cur!=at(i).end(); Cur++)
IndexStream.write(reinterpret_cast<char *>(&*Cur), sizeof(TFrameInfo));
IndexStream.write(reinterpret_cast<char *>(&TH), sizeof(TH));
IndexStream.write(reinterpret_cast<char *>(FFMS_GET_VECTOR_PTR(at(i))), TH.Frames * sizeof(TFrameInfo));
}
}
return 0;
}
int FFIndex::ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize) {
void FFMS_Index::ReadIndex(const char *IndexFile) {
ffms_fstream Index(IndexFile, std::ios::in | std::ios::binary);
if (!Index.is_open()) {
snprintf(ErrorMsg, MsgSize, "Failed to open '%s' for reading", IndexFile);
return 1;
}
if (!Index.is_open())
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_FILE_READ,
boost::format("Failed to open '%1%' for reading") % IndexFile);
// Read the index file header
IndexHeader IH;
Index.read(reinterpret_cast<char *>(&IH), sizeof(IH));
if (IH.Id != INDEXID) {
snprintf(ErrorMsg, MsgSize, "'%s' is not a valid index file", IndexFile);
return 2;
}
if (IH.Id != INDEXID)
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
boost::format("'%1%' is not a valid index file") % IndexFile);
if (IH.Version != INDEXVERSION) {
snprintf(ErrorMsg, MsgSize, "'%s' is not the expected index version", IndexFile);
return 3;
}
if (IH.Version != FFMS_VERSION)
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_VERSION,
boost::format("'%1%' is not the expected index version") % IndexFile);
if (IH.LAVUVersion != avutil_version() || IH.LAVFVersion != avformat_version() ||
IH.LAVCVersion != avcodec_version() || IH.LSWSVersion != swscale_version() ||
IH.LPPVersion != postproc_version()) {
snprintf(ErrorMsg, MsgSize, "A different FFmpeg build was used to create '%s'", IndexFile);
return 4;
}
IH.LPPVersion != postproc_version())
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_VERSION,
boost::format("A different FFmpeg build was used to create '%1%'") % IndexFile);
if (!(IH.Decoder & FFMS_GetEnabledSources()))
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_NOT_AVAILABLE,
"The source which this index was created with is not available");
Decoder = IH.Decoder;
Filesize = IH.FileSize;
memcpy(Digest, IH.FileSignature, sizeof(Digest));
try {
for (unsigned int i = 0; i < IH.Tracks; i++) {
// Read how many records belong to the current stream
uint32_t TT;
Index.read(reinterpret_cast<char *>(&TT), sizeof(TT));
int64_t Num;
Index.read(reinterpret_cast<char *>(&Num), sizeof(Num));
int64_t Den;
Index.read(reinterpret_cast<char *>(&Den), sizeof(Den));
int64_t Frames;
Index.read(reinterpret_cast<char *>(&Frames), sizeof(Frames));
push_back(FFTrack(Num, Den, static_cast<FFMS_TrackType>(TT)));
TrackHeader TH;
Index.read(reinterpret_cast<char *>(&TH), sizeof(TH));
push_back(FFMS_Track(TH.Num, TH.Den, static_cast<FFMS_TrackType>(TH.TT)));
TFrameInfo FI = TFrameInfo::VideoFrameInfo(0, 0, false);
for (size_t j = 0; j < Frames; j++) {
Index.read(reinterpret_cast<char *>(&FI), sizeof(TFrameInfo));
at(i).push_back(FI);
if (TH.Frames) {
at(i).resize(TH.Frames);
Index.read(reinterpret_cast<char *>(FFMS_GET_VECTOR_PTR(at(i))), TH.Frames * sizeof(TFrameInfo));
}
}
} catch (...) {
snprintf(ErrorMsg, MsgSize, "Unknown error while reading index information in '%s'", IndexFile);
return 5;
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_UNKNOWN,
boost::format("Unknown error while reading index information in '%1%'") % IndexFile);
}
}
return 0;
}
FFIndex::FFIndex() {
FFMS_Index::FFMS_Index() {
// this comment documents nothing
}
FFIndex::FFIndex(int64_t Filesize, uint8_t Digest[20]) {
FFMS_Index::FFMS_Index(int64_t Filesize, uint8_t Digest[20]) {
this->Filesize = Filesize;
memcpy(this->Digest, Digest, sizeof(this->Digest));
}
void FFIndexer::SetIndexMask(int IndexMask) {
void FFMS_Indexer::SetIndexMask(int IndexMask) {
this->IndexMask = IndexMask;
}
void FFIndexer::SetDumpMask(int DumpMask) {
void FFMS_Indexer::SetDumpMask(int DumpMask) {
this->DumpMask = DumpMask;
}
void FFIndexer::SetIgnoreDecodeErrors(bool IgnoreDecodeErrors) {
this->IgnoreDecodeErrors = IgnoreDecodeErrors;
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;
}
void FFIndexer::SetProgressCallback(TIndexCallback IC, void *ICPrivate) {
void FFMS_Indexer::SetProgressCallback(TIndexCallback IC, void *ICPrivate) {
this->IC = IC;
this->ICPrivate = ICPrivate;
}
void FFIndexer::SetAudioNameCallback(TAudioNameCallback ANC, void *ANCPrivate) {
void FFMS_Indexer::SetAudioNameCallback(TAudioNameCallback ANC, void *ANCPrivate) {
this->ANC = ANC;
this->ANCPrivate = ANCPrivate;
}
FFIndexer *FFIndexer::CreateFFIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize) {
FFMS_Indexer *FFMS_Indexer::CreateIndexer(const char *Filename) {
AVFormatContext *FormatContext = NULL;
if (av_open_input_file(&FormatContext, Filename, NULL, 0, NULL) != 0) {
snprintf(ErrorMsg, MsgSize, "Can't open '%s'", Filename);
return NULL;
}
if (av_open_input_file(&FormatContext, Filename, NULL, 0, NULL) != 0)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Can't open '%1%'") % Filename);
// Do matroska indexing instead?
if (!strcmp(FormatContext->iformat->name, "matroska")) {
av_close_input_file(FormatContext);
return new FFMatroskaIndexer(Filename, ErrorMsg, MsgSize);
return new FFMatroskaIndexer(Filename);
}
#ifdef HAALISOURCE
// Do haali ts indexing instead?
if (!strcmp(FormatContext->iformat->name, "mpeg") || !strcmp(FormatContext->iformat->name, "mpegts")) {
if (HasHaaliMPEG && (!strcmp(FormatContext->iformat->name, "mpeg") || !strcmp(FormatContext->iformat->name, "mpegts"))) {
av_close_input_file(FormatContext);
return new FFHaaliIndexer(Filename, 0, ErrorMsg, MsgSize);
return new FFHaaliIndexer(Filename, FFMS_SOURCE_HAALIMPEG);
}
if (!strcmp(FormatContext->iformat->name, "ogg")) {
if (HasHaaliOGG && !strcmp(FormatContext->iformat->name, "ogg")) {
av_close_input_file(FormatContext);
return new FFHaaliIndexer(Filename, 1, ErrorMsg, MsgSize);
return new FFHaaliIndexer(Filename, FFMS_SOURCE_HAALIOGG);
}
#endif
return new FFLAVFIndexer(Filename, FormatContext, ErrorMsg, MsgSize);
return new FFLAVFIndexer(Filename, FormatContext);
}
FFIndexer::FFIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize) : DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 5) {
if (FFIndex::CalculateFileSignature(Filename, &Filesize, Digest, ErrorMsg, MsgSize))
throw ErrorMsg;
FFMS_Indexer::FFMS_Indexer(const char *Filename) : DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 5) {
IndexMask = 0;
DumpMask = 0;
ErrorHandling = FFMS_IEH_CLEAR_TRACK;
IC = NULL;
ICPrivate = NULL;
ANC = NULL;
ANCPrivate = NULL;
FFMS_Index::CalculateFileSignature(Filename, &Filesize, Digest);
}
FFIndexer::~FFIndexer() {
FFMS_Indexer::~FFMS_Indexer() {
}
bool FFIndexer::WriteAudio(SharedAudioContext &AudioContext, FFIndex *Index, int Track, int DBSize, char *ErrorMsg, unsigned MsgSize) {
void FFMS_Indexer::WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize) {
// Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers.
if (DBSize > 0) {
if (!AudioContext.W64Writer) {
FFAudioProperties AP;
FFMS_AudioProperties AP;
FillAP(AP, AudioContext.CodecContext, (*Index)[Track]);
int FNSize = (*ANC)(SourceFile, Track, &AP, NULL, 0, ANCPrivate);
std::vector<char> WName(FNSize);
@ -428,13 +436,11 @@ bool FFIndexer::WriteAudio(SharedAudioContext &AudioContext, FFIndex *Index, int
AudioContext.W64Writer = new Wave64Writer(WN.c_str(), av_get_bits_per_sample_format(AudioContext.CodecContext->sample_fmt),
AudioContext.CodecContext->channels, AudioContext.CodecContext->sample_rate, (AudioContext.CodecContext->sample_fmt == SAMPLE_FMT_FLT) || (AudioContext.CodecContext->sample_fmt == SAMPLE_FMT_DBL));
} catch (...) {
snprintf(ErrorMsg, MsgSize, "Failed to write wave data");
return false;
throw FFMS_Exception(FFMS_ERROR_WAVE_WRITER, FFMS_ERROR_FILE_WRITE,
"Failed to write wave data");
}
}
AudioContext.W64Writer->WriteData(&DecodingBuffer[0], DBSize);
}
return true;
}

View file

@ -37,8 +37,7 @@
# include "guids.h"
#endif
#define INDEXVERSION 28
#define INDEXID 0x53920873
class SharedVideoContext {
private:
@ -69,52 +68,55 @@ struct TFrameInfo {
public:
FFMS_FRAMEINFO_COMMON
int64_t SampleStart;
unsigned int SampleCount;
int64_t FilePos;
unsigned int FrameSize;
size_t OriginalPos;
TFrameInfo();
static TFrameInfo VideoFrameInfo(int64_t DTS, int RepeatPict, bool KeyFrame, int64_t FilePos = 0, unsigned int FrameSize = 0);
static TFrameInfo AudioFrameInfo(int64_t DTS, int64_t SampleStart, bool KeyFrame, int64_t FilePos = 0, unsigned int FrameSize = 0);
static TFrameInfo AudioFrameInfo(int64_t DTS, int64_t SampleStart, unsigned int SampleCount, bool KeyFrame, int64_t FilePos = 0, unsigned int FrameSize = 0);
private:
TFrameInfo(int64_t DTS, int64_t SampleStart, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize);
TFrameInfo(int64_t DTS, int64_t SampleStart, unsigned int SampleCount, int RepeatPict, bool KeyFrame, int64_t FilePos, unsigned int FrameSize);
};
class FFTrack : public std::vector<TFrameInfo> {
class FFMS_Track : public std::vector<TFrameInfo> {
public:
FFMS_TrackType TT;
FFTrackTimeBase TB;
FFMS_TrackTimeBase TB;
int FindClosestVideoKeyFrame(int Frame);
int FindClosestAudioKeyFrame(int64_t Sample);
int FrameFromDTS(int64_t DTS);
int ClosestFrameFromDTS(int64_t DTS);
int WriteTimecodes(const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize);
void WriteTimecodes(const char *TimecodeFile);
FFTrack();
FFTrack(int64_t Num, int64_t Den, FFMS_TrackType TT);
FFMS_Track();
FFMS_Track(int64_t Num, int64_t Den, FFMS_TrackType TT);
};
class FFIndex : public std::vector<FFTrack> {
class FFMS_Index : public std::vector<FFMS_Track> {
public:
static int CalculateFileSignature(const char *Filename, int64_t *Filesize, uint8_t Digest[20], char *ErrorMsg, unsigned MsgSize);
static void CalculateFileSignature(const char *Filename, int64_t *Filesize, uint8_t Digest[20]);
int Decoder;
int64_t Filesize;
uint8_t Digest[20];
void Sort();
int CompareFileSignature(const char *Filename, char *ErrorMsg, unsigned MsgSize);
int WriteIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
int ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
bool CompareFileSignature(const char *Filename);
void WriteIndex(const char *IndexFile);
void ReadIndex(const char *IndexFile);
FFIndex();
FFIndex(int64_t Filesize, uint8_t Digest[20]);
FFMS_Index();
FFMS_Index(int64_t Filesize, uint8_t Digest[20]);
};
class FFIndexer {
class FFMS_Indexer {
protected:
int IndexMask;
int DumpMask;
bool IgnoreDecodeErrors;
int ErrorHandling;
TIndexCallback IC;
void *ICPrivate;
TAudioNameCallback ANC;
@ -125,43 +127,43 @@ protected:
int64_t Filesize;
uint8_t Digest[20];
bool WriteAudio(SharedAudioContext &AudioContext, FFIndex *Index, int Track, int DBSize, char *ErrorMsg, unsigned MsgSize);
void WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize);
public:
static FFIndexer *CreateFFIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize);
FFIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize);
virtual ~FFIndexer();
static FFMS_Indexer *CreateIndexer(const char *Filename);
FFMS_Indexer(const char *Filename);
virtual ~FFMS_Indexer();
void SetIndexMask(int IndexMask);
void SetDumpMask(int DumpMask);
void SetIgnoreDecodeErrors(bool IgnoreDecodeErrors);
void SetErrorHandling(int ErrorHandling);
void SetProgressCallback(TIndexCallback IC, void *ICPrivate);
void SetAudioNameCallback(TAudioNameCallback ANC, void *ANCPrivate);
virtual FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize) = 0;
virtual FFMS_Index *DoIndexing() = 0;
virtual int GetNumberOfTracks() = 0;
virtual FFMS_TrackType GetTrackType(int Track) = 0;
virtual const char *GetTrackCodec(int Track) = 0;
};
class FFLAVFIndexer : public FFIndexer {
class FFLAVFIndexer : public FFMS_Indexer {
private:
AVFormatContext *FormatContext;
public:
FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext, char *ErrorMsg, unsigned MsgSize);
FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext);
~FFLAVFIndexer();
FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize);
FFMS_Index *DoIndexing();
int GetNumberOfTracks();
FFMS_TrackType GetTrackType(int Track);
const char *GetTrackCodec(int Track);
};
class FFMatroskaIndexer : public FFIndexer {
class FFMatroskaIndexer : public FFMS_Indexer {
private:
MatroskaFile *MF;
MatroskaReaderContext MC;
AVCodec *Codec[32];
public:
FFMatroskaIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize);
FFMatroskaIndexer(const char *Filename);
~FFMatroskaIndexer();
FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize);
FFMS_Index *DoIndexing();
int GetNumberOfTracks();
FFMS_TrackType GetTrackType(int Track);
const char *GetTrackCodec(int Track);
@ -169,7 +171,7 @@ public:
#ifdef HAALISOURCE
class FFHaaliIndexer : public FFIndexer {
class FFHaaliIndexer : public FFMS_Indexer {
private:
int SourceMode;
CComPtr<IMMContainer> pMMC;
@ -181,8 +183,8 @@ private:
CComQIPtr<IPropertyBag> PropertyBags[32];
int64_t Duration;
public:
FFHaaliIndexer(const char *Filename, int SourceMode, char *ErrorMsg, unsigned MsgSize);
FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize);
FFHaaliIndexer(const char *Filename, enum FFMS_Sources SourceMode);
FFMS_Index *DoIndexing();
int GetNumberOfTracks();
FFMS_TrackType GetTrackType(int Track);
const char *GetTrackCodec(int Track);

View file

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffaudiosource.h"
#include "audiosource.h"
void FFLAVFAudio::Free(bool CloseCodec) {
if (CloseCodec)
@ -27,75 +27,53 @@ void FFLAVFAudio::Free(bool CloseCodec) {
av_close_input_file(FormatContext);
}
FFLAVFAudio::FFLAVFAudio(const char *SourceFile, int Track, FFIndex *Index,
char *ErrorMsg, unsigned MsgSize)
: FFAudio(SourceFile, Index, ErrorMsg, MsgSize){
FFLAVFAudio::FFLAVFAudio(const char *SourceFile, int Track, FFMS_Index *Index)
: Res(FFSourceResources<FFMS_AudioSource>(this)), FFMS_AudioSource(SourceFile, Index, Track){
FormatContext = NULL;
AVCodec *Codec = NULL;
AudioTrack = Track;
Frames = (*Index)[AudioTrack];
if (Frames.size() == 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Audio track contains no frames, was it indexed properly?");
throw ErrorMsg;
}
if (av_open_input_file(&FormatContext, SourceFile, NULL, 0, NULL) != 0) {
snprintf(ErrorMsg, MsgSize, "Couldn't open '%s'", SourceFile);
throw ErrorMsg;
}
if (av_find_stream_info(FormatContext) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Couldn't find stream information");
throw ErrorMsg;
}
LAVFOpenFile(SourceFile, FormatContext);
CodecContext = FormatContext->streams[AudioTrack]->codec;
Codec = avcodec_find_decoder(CodecContext->codec_id);
if (Codec == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Audio codec not found");
throw ErrorMsg;
}
if (Codec == NULL)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Audio codec not found");
if (avcodec_open(CodecContext, Codec) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
throw ErrorMsg;
}
if (avcodec_open(CodecContext, Codec) < 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Could not open audio codec");
Res.CloseCodec(true);
// Always try to decode a frame to make sure all required parameters are known
int64_t Dummy;
if (DecodeNextAudioBlock(&Dummy, ErrorMsg, MsgSize) < 0) {
Free(true);
throw ErrorMsg;
}
DecodeNextAudioBlock(&Dummy);
if (av_seek_frame(FormatContext, AudioTrack, Frames[0].DTS, AVSEEK_FLAG_BACKWARD) < 0)
av_seek_frame(FormatContext, AudioTrack, Frames[0].DTS, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY);
avcodec_flush_buffers(CodecContext);
FillAP(AP, CodecContext, Frames);
if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0) {
Free(true);
snprintf(ErrorMsg, MsgSize, "Codec returned zero size audio");
throw ErrorMsg;
}
if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Codec returned zero size audio");
AudioCache.Initialize((AP.Channels * AP.BitsPerSample) / 8, 50);
}
int FFLAVFAudio::DecodeNextAudioBlock(int64_t *Count, char *ErrorMsg, unsigned MsgSize) {
void FFLAVFAudio::DecodeNextAudioBlock(int64_t *Count) {
const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8;
int Ret = -1;
*Count = 0;
uint8_t *Buf = &DecodingBuffer[0];
AVPacket Packet, TempPacket;
InitNullPacket(&Packet);
InitNullPacket(&TempPacket);
InitNullPacket(Packet);
InitNullPacket(TempPacket);
while (av_read_frame(FormatContext, &Packet) >= 0) {
if (Packet.stream_index == AudioTrack) {
@ -127,11 +105,12 @@ int FFLAVFAudio::DecodeNextAudioBlock(int64_t *Count, char *ErrorMsg, unsigned M
av_free_packet(&Packet);
}
Done:
return Ret;
Done:;
}
int FFLAVFAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize) {
void FFLAVFAudio::GetAudio(void *Buf, int64_t Start, int64_t Count) {
GetAudioCheck(Start, Count);
const int64_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8;
memset(Buf, 0, static_cast<size_t>(SizeConst * Count));
@ -142,7 +121,7 @@ int FFLAVFAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMs
int64_t CacheEnd = AudioCache.FillRequest(Start, Count, DstBuf);
// Was everything in the cache?
if (CacheEnd == Start + Count)
return 0;
return;
size_t CurrentAudioBlock;
// Is seeking required to decode the requested samples?
@ -158,7 +137,7 @@ int FFLAVFAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMs
avcodec_flush_buffers(CodecContext);
AVPacket Packet;
InitNullPacket(&Packet);
InitNullPacket(Packet);
// Establish where we actually are
// Trigger on packet dts difference since groups can otherwise be indistinguishable
@ -189,11 +168,7 @@ int FFLAVFAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMs
int64_t DecodeCount;
do {
int Ret = DecodeNextAudioBlock(&DecodeCount, ErrorMsg, MsgSize);
if (Ret < 0) {
// FIXME
//Env->ThrowError("Bleh, bad audio decoding");
}
DecodeNextAudioBlock(&DecodeCount);
// Cache the block if enough blocks before it have been decoded to avoid garbage
if (PreDecBlocks == 0) {
@ -207,10 +182,4 @@ int FFLAVFAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMs
if (CurrentAudioBlock < Frames.size())
CurrentSample = Frames[CurrentAudioBlock].SampleStart;
} while (Start + Count - CacheEnd > 0 && CurrentAudioBlock < Frames.size());
return 0;
}
FFLAVFAudio::~FFLAVFAudio() {
Free(true);
}

View file

@ -22,14 +22,14 @@
FFLAVFIndexer::FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext, char *ErrorMsg, unsigned MsgSize) : FFIndexer(Filename, ErrorMsg, MsgSize) {
FFLAVFIndexer::FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext) : FFMS_Indexer(Filename) {
SourceFile = Filename;
this->FormatContext = FormatContext;
if (av_find_stream_info(FormatContext) < 0) {
av_close_input_file(FormatContext);
snprintf(ErrorMsg, MsgSize, "Couldn't find stream information");
throw ErrorMsg;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
"Couldn't find stream information");
}
}
@ -37,15 +37,15 @@ FFLAVFIndexer::~FFLAVFIndexer() {
av_close_input_file(FormatContext);
}
FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
FFMS_Index *FFLAVFIndexer::DoIndexing() {
std::vector<SharedAudioContext> AudioContexts(FormatContext->nb_streams, SharedAudioContext(false));
std::vector<SharedVideoContext> VideoContexts(FormatContext->nb_streams, SharedVideoContext(false));
std::auto_ptr<FFIndex> TrackIndices(new FFIndex(Filesize, Digest));
TrackIndices->Decoder = 0;
std::auto_ptr<FFMS_Index> TrackIndices(new FFMS_Index(Filesize, Digest));
TrackIndices->Decoder = FFMS_SOURCE_LAVF;
for (unsigned int i = 0; i < FormatContext->nb_streams; i++) {
TrackIndices->push_back(FFTrack((int64_t)FormatContext->streams[i]->time_base.num * 1000,
TrackIndices->push_back(FFMS_Track((int64_t)FormatContext->streams[i]->time_base.num * 1000,
FormatContext->streams[i]->time_base.den,
static_cast<FFMS_TrackType>(FormatContext->streams[i]->codec->codec_type)));
@ -53,15 +53,13 @@ FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
(VideoContexts[i].Parser = av_parser_init(FormatContext->streams[i]->codec->codec_id))) {
AVCodec *VideoCodec = avcodec_find_decoder(FormatContext->streams[i]->codec->codec_id);
if (VideoCodec == NULL) {
snprintf(ErrorMsg, MsgSize, "Vudio codec not found");
return NULL;
}
if (VideoCodec == NULL)
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
"Video codec not found");
if (avcodec_open(FormatContext->streams[i]->codec, VideoCodec) < 0) {
snprintf(ErrorMsg, MsgSize, "Could not open video codec");
return NULL;
}
if (avcodec_open(FormatContext->streams[i]->codec, VideoCodec) < 0)
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Could not open video codec");
VideoContexts[i].CodecContext = FormatContext->streams[i]->codec;
VideoContexts[i].Parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
@ -71,15 +69,13 @@ FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
AVCodecContext *AudioCodecContext = FormatContext->streams[i]->codec;
AVCodec *AudioCodec = avcodec_find_decoder(AudioCodecContext->codec_id);
if (AudioCodec == NULL) {
snprintf(ErrorMsg, MsgSize, "Audio codec not found");
return NULL;
}
if (AudioCodec == NULL)
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
"Audio codec not found");
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
return NULL;
}
if (avcodec_open(AudioCodecContext, AudioCodec) < 0)
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Could not open audio codec");
AudioContexts[i].CodecContext = AudioCodecContext;
} else {
@ -90,15 +86,14 @@ FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
//
AVPacket Packet, TempPacket;
InitNullPacket(&Packet);
InitNullPacket(&TempPacket);
InitNullPacket(Packet);
InitNullPacket(TempPacket);
while (av_read_frame(FormatContext, &Packet) >= 0) {
// Update progress
if (IC) {
if ((*IC)(FormatContext->pb->pos, FormatContext->file_size, ICPrivate)) {
snprintf(ErrorMsg, MsgSize, "Cancelled by user");
return NULL;
}
if ((*IC)(FormatContext->pb->pos, FormatContext->file_size, ICPrivate))
throw FFMS_Exception(FFMS_ERROR_CANCELLED, FFMS_ERROR_USER,
"Cancelled by user");
}
// Only create index entries for video for now to save space
@ -114,7 +109,7 @@ FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
(*TrackIndices)[Packet.stream_index].push_back(TFrameInfo::VideoFrameInfo(Packet.dts, RepeatPict, (Packet.flags & AV_PKT_FLAG_KEY) ? 1 : 0));
} else if (FormatContext->streams[Packet.stream_index]->codec->codec_type == CODEC_TYPE_AUDIO && (IndexMask & (1 << Packet.stream_index))) {
(*TrackIndices)[Packet.stream_index].push_back(TFrameInfo::AudioFrameInfo(Packet.dts, AudioContexts[Packet.stream_index].CurrentSample, (Packet.flags & AV_PKT_FLAG_KEY) ? 1 : 0));
int64_t StartSample = AudioContexts[Packet.stream_index].CurrentSample;
AVCodecContext *AudioCodecContext = FormatContext->streams[Packet.stream_index]->codec;
TempPacket.data = Packet.data;
TempPacket.size = Packet.size;
@ -124,13 +119,18 @@ FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10;
int Ret = avcodec_decode_audio3(AudioCodecContext, &DecodingBuffer[0], &dbsize, &TempPacket);
if (Ret < 0) {
if (IgnoreDecodeErrors) {
if (ErrorHandling == FFMS_IEH_ABORT) {
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Audio decoding error");
} else if (ErrorHandling == FFMS_IEH_CLEAR_TRACK) {
(*TrackIndices)[Packet.stream_index].clear();
IndexMask &= ~(1 << Packet.stream_index);
break;
} else {
snprintf(ErrorMsg, MsgSize, "Audio decoding error");
return NULL;
} else if (ErrorHandling == FFMS_IEH_STOP_TRACK) {
IndexMask &= ~(1 << Packet.stream_index);
break;
} else if (ErrorHandling == FFMS_IEH_IGNORE) {
break;
}
}
@ -143,8 +143,11 @@ FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
AudioContexts[Packet.stream_index].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels);
if (DumpMask & (1 << Packet.stream_index))
WriteAudio(AudioContexts[Packet.stream_index], TrackIndices.get(), Packet.stream_index, dbsize, ErrorMsg, MsgSize);
WriteAudio(AudioContexts[Packet.stream_index], TrackIndices.get(), Packet.stream_index, dbsize);
}
(*TrackIndices)[Packet.stream_index].push_back(TFrameInfo::AudioFrameInfo(Packet.dts, StartSample,
static_cast<unsigned int>(AudioContexts[Packet.stream_index].CurrentSample - StartSample), (Packet.flags & AV_PKT_FLAG_KEY) ? 1 : 0));
}
av_free_packet(&Packet);
@ -163,5 +166,5 @@ FFMS_TrackType FFLAVFIndexer::GetTrackType(int Track) {
}
const char *FFLAVFIndexer::GetTrackCodec(int Track) {
return (avcodec_find_decoder(FormatContext->streams[Track]->codec->codec_id))->long_name;
return (avcodec_find_decoder(FormatContext->streams[Track]->codec->codec_id))->name;
}

View file

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffvideosource.h"
#include "videosource.h"
@ -28,9 +28,9 @@ void FFLAVFVideo::Free(bool CloseCodec) {
av_close_input_file(FormatContext);
}
FFLAVFVideo::FFLAVFVideo(const char *SourceFile, int Track, FFIndex *Index,
const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize)
: FFVideo(SourceFile, Index, ErrorMsg, MsgSize) {
FFLAVFVideo::FFLAVFVideo(const char *SourceFile, int Track, FFMS_Index *Index,
int Threads, int SeekMode)
: Res(FFSourceResources<FFMS_VideoSource>(this)), FFMS_VideoSource(SourceFile, Index, Track) {
FormatContext = NULL;
AVCodec *Codec = NULL;
@ -38,68 +38,45 @@ FFLAVFVideo::FFLAVFVideo(const char *SourceFile, int Track, FFIndex *Index,
VideoTrack = Track;
Frames = (*Index)[VideoTrack];
if (Frames.size() == 0) {
snprintf(ErrorMsg, MsgSize, "Video track contains no frames");
throw ErrorMsg;
}
LAVFOpenFile(SourceFile, FormatContext);
if (av_open_input_file(&FormatContext, SourceFile, NULL, 0, NULL) != 0) {
snprintf(ErrorMsg, MsgSize, "Couldn't open '%s'", SourceFile);
throw ErrorMsg;
}
if (av_find_stream_info(FormatContext) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Couldn't find stream information");
throw ErrorMsg;
}
if (SeekMode >= 0 && av_seek_frame(FormatContext, VideoTrack, Frames[0].DTS, AVSEEK_FLAG_BACKWARD) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Video track is unseekable");
throw ErrorMsg;
}
if (SeekMode >= 0 && av_seek_frame(FormatContext, VideoTrack, Frames[0].DTS, AVSEEK_FLAG_BACKWARD) < 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Video track is unseekable");
CodecContext = FormatContext->streams[VideoTrack]->codec;
CodecContext->thread_count = Threads;
Codec = avcodec_find_decoder(CodecContext->codec_id);
if (Codec == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Video codec not found");
throw ErrorMsg;
}
if (Codec == NULL)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Video codec not found");
if (avcodec_open(CodecContext, Codec) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Could not open video codec");
throw ErrorMsg;
}
if (avcodec_open(CodecContext, Codec) < 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Could not open video codec");
Res.CloseCodec(true);
// Always try to decode a frame to make sure all required parameters are known
int64_t Dummy;
if (DecodeNextFrame(&Dummy, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
DecodeNextFrame(&Dummy);
//VP.image_type = VideoInfo::IT_TFF;
VP.Width = CodecContext->width;
VP.Height = CodecContext->height;
VP.FPSDenominator = FormatContext->streams[VideoTrack]->time_base.num;
VP.FPSNumerator = FormatContext->streams[VideoTrack]->time_base.den;
VP.RFFDenominator = CodecContext->time_base.num;
VP.RFFNumerator = CodecContext->time_base.den;
VP.NumFrames = Frames.size();
VP.VPixelFormat = CodecContext->pix_fmt;
VP.TopFieldFirst = DecodeFrame->top_field_first;
VP.ColorSpace = CodecContext->colorspace;
VP.ColorRange = CodecContext->color_range;
VP.FirstTime = ((Frames.front().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
VP.LastTime = ((Frames.back().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
if (VP.Width <= 0 || VP.Height <= 0) {
Free(true);
snprintf(ErrorMsg, MsgSize, "Codec returned zero size video");
throw ErrorMsg;
}
if (CodecContext->width <= 0 || CodecContext->height <= 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Codec returned zero size video");
// sanity check framerate
if (VP.FPSDenominator > VP.FPSNumerator || VP.FPSDenominator <= 0 || VP.FPSNumerator <= 0) {
@ -107,11 +84,6 @@ FFLAVFVideo::FFLAVFVideo(const char *SourceFile, int Track, FFIndex *Index,
VP.FPSNumerator = 30;
}
if (InitPP(PP, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
// Adjust framerate to match the duration of the first frame
if (Frames.size() >= 2) {
unsigned int DTSDiff = (unsigned int)FFMAX(Frames[1].DTS - Frames[0].DTS, 1);
@ -120,23 +92,16 @@ FFLAVFVideo::FFLAVFVideo(const char *SourceFile, int Track, FFIndex *Index,
// Cannot "output" to PPFrame without doing all other initialization
// This is the additional mess required for seekmode=-1 to work in a reasonable way
if (!OutputFrame(DecodeFrame, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
OutputFrame(DecodeFrame);
// Set AR variables
VP.SARNum = CodecContext->sample_aspect_ratio.num;
VP.SARDen = CodecContext->sample_aspect_ratio.den;
}
FFLAVFVideo::~FFLAVFVideo() {
Free(true);
}
int FFLAVFVideo::DecodeNextFrame(int64_t *AStartTime, char *ErrorMsg, unsigned MsgSize) {
void FFLAVFVideo::DecodeNextFrame(int64_t *AStartTime) {
AVPacket Packet;
InitNullPacket(&Packet);
InitNullPacket(Packet);
int FrameFinished = 0;
*AStartTime = -1;
@ -145,6 +110,11 @@ int FFLAVFVideo::DecodeNextFrame(int64_t *AStartTime, char *ErrorMsg, unsigned M
if (*AStartTime < 0)
*AStartTime = Packet.dts;
if (CodecContext->codec_id == CODEC_ID_MPEG4 && IsNVOP(Packet)) {
av_free_packet(&Packet);
goto Done;
}
avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet);
}
@ -157,23 +127,22 @@ int FFLAVFVideo::DecodeNextFrame(int64_t *AStartTime, char *ErrorMsg, unsigned M
// Flush the last frames
if (CodecContext->has_b_frames) {
AVPacket NullPacket;
InitNullPacket(&NullPacket);
InitNullPacket(NullPacket);
avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket);
}
if (!FrameFinished)
goto Error;
// Ignore errors for now
Error:
Done:
return 0;
Done:;
}
FFAVFrame *FFLAVFVideo::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) {
// PPFrame always holds frame LastFrameNum even if no PP is applied
FFMS_Frame *FFLAVFVideo::GetFrame(int n) {
GetFrameCheck(n);
if (LastFrameNum == n)
return OutputFrame(DecodeFrame, ErrorMsg, MsgSize);
return &LocalFrame;
bool HasSeeked = false;
int SeekOffset = 0;
@ -200,14 +169,13 @@ ReSeek:
}
}
} else if (n < CurrentFrame) {
snprintf(ErrorMsg, MsgSize, "Non-linear access attempted");
return NULL;
throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_INVALID_ARGUMENT,
"Non-linear access attempted");
}
do {
int64_t StartTime;
if (DecodeNextFrame(&StartTime, ErrorMsg, MsgSize))
return NULL;
DecodeNextFrame(&StartTime);
if (HasSeeked) {
HasSeeked = false;
@ -217,10 +185,10 @@ ReSeek:
switch (SeekMode) {
case 1:
// No idea where we are so go back a bit further
if (ClosestKF + SeekOffset == 0) {
snprintf(ErrorMsg, MsgSize, "Frame accurate seeking is not possible in this file\n");
return NULL;
}
if (ClosestKF + SeekOffset == 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Frame accurate seeking is not possible in this file");
SeekOffset -= FFMIN(10, ClosestKF + SeekOffset);
goto ReSeek;
@ -229,8 +197,8 @@ ReSeek:
CurrentFrame = Frames.ClosestFrameFromDTS(StartTime);
break;
default:
snprintf(ErrorMsg, MsgSize, "Failed assertion");
return NULL;
throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_UNKNOWN,
"Failed assertion");
}
}
}
@ -239,5 +207,5 @@ ReSeek:
} while (CurrentFrame <= n);
LastFrameNum = n;
return OutputFrame(DecodeFrame, ErrorMsg, MsgSize);
return OutputFrame(DecodeFrame);
}

View file

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffaudiosource.h"
#include "audiosource.h"
void FFMatroskaAudio::Free(bool CloseCodec) {
if (CS)
@ -32,89 +32,74 @@ void FFMatroskaAudio::Free(bool CloseCodec) {
av_freep(&CodecContext);
}
FFMatroskaAudio::FFMatroskaAudio(const char *SourceFile, int Track,
FFIndex *Index, char *ErrorMsg, unsigned MsgSize)
: FFAudio(SourceFile, Index, ErrorMsg, MsgSize) {
FFMatroskaAudio::FFMatroskaAudio(const char *SourceFile, int Track, FFMS_Index *Index)
: Res(FFSourceResources<FFMS_AudioSource>(this)), FFMS_AudioSource(SourceFile, Index, Track) {
CodecContext = NULL;
AVCodec *Codec = NULL;
TrackInfo *TI = NULL;
CS = NULL;
PacketNumber = 0;
Frames = (*Index)[Track];
if (Frames.size() == 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Audio track contains no frames, was it indexed properly?");
throw ErrorMsg;
}
MC.ST.fp = ffms_fopen(SourceFile, "rb");
if (MC.ST.fp == NULL) {
snprintf(ErrorMsg, MsgSize, "Can't open '%s': %s", SourceFile, strerror(errno));
throw ErrorMsg;
}
if (MC.ST.fp == NULL)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Can't open '%1%': %2%") % SourceFile % strerror(errno));
setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage));
if (MF == NULL) {
fclose(MC.ST.fp);
snprintf(ErrorMsg, MsgSize, "Can't parse Matroska file: %s", ErrorMessage);
throw ErrorMsg;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Can't parse Matroska file: %1%") % ErrorMessage);
}
mkv_SetTrackMask(MF, ~(1 << Track));
TI = mkv_GetTrackInfo(MF, Track);
if (TI->CompEnabled) {
CS = cs_Create(MF, Track, ErrorMessage, sizeof(ErrorMessage));
if (CS == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Can't create decompressor: %s", ErrorMessage);
throw ErrorMsg;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
boost::format("Can't create decompressor: %1%") % ErrorMessage);
}
}
CodecContext = avcodec_alloc_context();
Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate));
if (Codec == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Video codec not found");
throw ErrorMsg;
}
if (Codec == NULL)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Audio codec not found");
InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext);
if (avcodec_open(CodecContext, Codec) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Could not open video codec");
throw ErrorMsg;
}
if (avcodec_open(CodecContext, Codec) < 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Could not open audio codec");
Res.CloseCodec(true);
// Always try to decode a frame to make sure all required parameters are known
int64_t Dummy;
if (DecodeNextAudioBlock(&Dummy, 0, ErrorMsg, MsgSize) < 0) {
Free(true);
throw ErrorMsg;
}
DecodeNextAudioBlock(&Dummy);
avcodec_flush_buffers(CodecContext);
FillAP(AP, CodecContext, Frames);
if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0) {
Free(true);
snprintf(ErrorMsg, MsgSize, "Codec returned zero size audio");
throw ErrorMsg;
}
if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Codec returned zero size audio");
AudioCache.Initialize((AP.Channels * AP.BitsPerSample) / 8, 50);
}
FFMatroskaAudio::~FFMatroskaAudio() {
Free(true);
}
void FFMatroskaAudio::GetAudio(void *Buf, int64_t Start, int64_t Count) {
GetAudioCheck(Start, Count);
int FFMatroskaAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize) {
const int64_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8;
memset(Buf, 0, static_cast<size_t>(SizeConst * Count));
@ -125,58 +110,50 @@ int FFMatroskaAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *Err
int64_t CacheEnd = AudioCache.FillRequest(Start, Count, DstBuf);
// Was everything in the cache?
if (CacheEnd == Start + Count)
return 0;
return;
int CurrentAudioBlock;
// Is seeking required to decode the requested samples?
// if (!(CurrentSample >= Start && CurrentSample <= CacheEnd)) {
if (CurrentSample != CacheEnd) {
PreDecBlocks = 15;
CurrentAudioBlock = FFMAX((int64_t)Frames.FindClosestAudioKeyFrame(CacheEnd) - PreDecBlocks, (int64_t)0);
PacketNumber = FFMAX((int64_t)Frames.FindClosestAudioKeyFrame(CacheEnd) - PreDecBlocks, (int64_t)0);;
avcodec_flush_buffers(CodecContext);
} else {
CurrentAudioBlock = Frames.FindClosestAudioKeyFrame(CurrentSample);
}
int64_t DecodeCount;
do {
int Ret = DecodeNextAudioBlock(&DecodeCount, CurrentAudioBlock, ErrorMsg, MsgSize);
if (Ret < 0) {
// FIXME
//Env->ThrowError("Bleh, bad audio decoding");
}
const TFrameInfo &FI = Frames[Frames[PacketNumber].OriginalPos];
DecodeNextAudioBlock(&DecodeCount);
// Cache the block if enough blocks before it have been decoded to avoid garbage
if (PreDecBlocks == 0) {
AudioCache.CacheBlock(Frames[CurrentAudioBlock].SampleStart, DecodeCount, &DecodingBuffer[0]);
AudioCache.CacheBlock(FI.SampleStart, DecodeCount, &DecodingBuffer[0]);
CacheEnd = AudioCache.FillRequest(CacheEnd, Start + Count - CacheEnd, DstBuf + (CacheEnd - Start) * SizeConst);
} else {
PreDecBlocks--;
}
CurrentAudioBlock++;
if (CurrentAudioBlock < static_cast<int>(Frames.size()))
CurrentSample = Frames[CurrentAudioBlock].SampleStart;
} while (Start + Count - CacheEnd > 0 && CurrentAudioBlock < static_cast<int>(Frames.size()));
return 0;
} while (Start + Count - CacheEnd > 0 && PacketNumber < Frames.size());
}
int FFMatroskaAudio::DecodeNextAudioBlock(int64_t *Count, int AudioBlock, char *ErrorMsg, unsigned MsgSize) {
void FFMatroskaAudio::DecodeNextAudioBlock(int64_t *Count) {
const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8;
int Ret = -1;
*Count = 0;
uint8_t *Buf = &DecodingBuffer[0];
AVPacket TempPacket;
InitNullPacket(&TempPacket);
InitNullPacket(TempPacket);
unsigned int FrameSize = Frames[AudioBlock].FrameSize;
if (ReadFrame(Frames[AudioBlock].FilePos, FrameSize, CS, MC, ErrorMsg, MsgSize))
return 1;
const TFrameInfo &FI = Frames[Frames[PacketNumber].OriginalPos];
unsigned int FrameSize = FI.FrameSize;
CurrentSample = FI.SampleStart + FI.SampleCount;
PacketNumber++;
ReadFrame(FI.FilePos, FrameSize, CS, MC);
TempPacket.data = MC.Buffer;
TempPacket.size = FrameSize;
if (Frames[AudioBlock].KeyFrame)
if (FI.KeyFrame)
TempPacket.flags = AV_PKT_FLAG_KEY;
else
TempPacket.flags = 0;
@ -197,6 +174,5 @@ int FFMatroskaAudio::DecodeNextAudioBlock(int64_t *Count, int AudioBlock, char *
}
}
Done:
return 0;
Done:;
}

View file

@ -23,25 +23,26 @@
FFMatroskaIndexer::FFMatroskaIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize) : FFIndexer(Filename, ErrorMsg, MsgSize) {
memset(Codec, 0, sizeof(Codec));
FFMatroskaIndexer::FFMatroskaIndexer(const char *Filename) : FFMS_Indexer(Filename) {
SourceFile = Filename;
char ErrorMessage[256];
for (int i = 0; i < 32; i++) {
Codec[i] = NULL;
}
InitStdIoStream(&MC.ST);
MC.ST.fp = ffms_fopen(SourceFile, "rb");
if (MC.ST.fp == NULL) {
snprintf(ErrorMsg, MsgSize, "Can't open '%s': %s", SourceFile, strerror(errno));
throw ErrorMsg;
}
if (MC.ST.fp == NULL)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Can't open '%1%': %2%") % SourceFile % strerror(errno));
setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage));
if (MF == NULL) {
fclose(MC.ST.fp);
snprintf(ErrorMsg, MsgSize, "Can't parse Matroska file: %s", ErrorMessage);
throw ErrorMsg;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Can't parse Matroska file: %1%") % ErrorMessage);
}
for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) {
@ -55,17 +56,17 @@ FFMatroskaIndexer::~FFMatroskaIndexer() {
fclose(MC.ST.fp);
}
FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
FFMS_Index *FFMatroskaIndexer::DoIndexing() {
char ErrorMessage[256];
std::vector<SharedAudioContext> AudioContexts(mkv_GetNumTracks(MF), SharedAudioContext(true));
std::vector<SharedVideoContext> VideoContexts(mkv_GetNumTracks(MF), SharedVideoContext(true));
std::auto_ptr<FFIndex> TrackIndices(new FFIndex(Filesize, Digest));
TrackIndices->Decoder = 1;
std::auto_ptr<FFMS_Index> TrackIndices(new FFMS_Index(Filesize, Digest));
TrackIndices->Decoder = FFMS_SOURCE_MATROSKA;
for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) {
TrackInfo *TI = mkv_GetTrackInfo(MF, i);
TrackIndices->push_back(FFTrack(mkv_TruncFloat(mkv_GetTrackInfo(MF, i)->TimecodeScale), 1000000, HaaliTrackTypeToFFTrackType(mkv_GetTrackInfo(MF, i)->Type)));
TrackIndices->push_back(FFMS_Track(mkv_TruncFloat(mkv_GetTrackInfo(MF, i)->TimecodeScale), 1000000, HaaliTrackTypeToFFTrackType(mkv_GetTrackInfo(MF, i)->Type)));
if (HaaliTrackTypeToFFTrackType(TI->Type) == FFMS_TYPE_VIDEO && Codec[i] && (VideoContexts[i].Parser = av_parser_init(Codec[i]->id))) {
@ -75,16 +76,15 @@ FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
if (avcodec_open(CodecContext, Codec[i]) < 0) {
av_freep(&CodecContext);
snprintf(ErrorMsg, MsgSize, "Could not open video codec");
return NULL;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Could not open video codec");
}
if (TI->CompEnabled) {
VideoContexts[i].CS = cs_Create(MF, i, ErrorMessage, sizeof(ErrorMessage));
if (VideoContexts[i].CS == NULL) {
snprintf(ErrorMsg, MsgSize, "Can't create decompressor: %s", ErrorMessage);
return NULL;
}
if (VideoContexts[i].CS == NULL)
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
boost::format("Can't create decompressor: %1%") % ErrorMessage);
}
VideoContexts[i].CodecContext = CodecContext;
@ -102,8 +102,8 @@ FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
if (AudioContexts[i].CS == NULL) {
av_freep(&AudioCodecContext);
AudioContexts[i].CodecContext = NULL;
snprintf(ErrorMsg, MsgSize, "Can't create decompressor: %s", ErrorMessage);
return NULL;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
boost::format("Can't create decompressor: %1%") % ErrorMessage);
}
}
@ -111,15 +111,15 @@ FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
if (AudioCodec == NULL) {
av_freep(&AudioCodecContext);
AudioContexts[i].CodecContext = NULL;
snprintf(ErrorMsg, MsgSize, "Audio codec not found");
return NULL;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
"Audio codec not found");
}
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
av_freep(&AudioCodecContext);
AudioContexts[i].CodecContext = NULL;
snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
return NULL;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Could not open audio codec");
}
} else {
IndexMask &= ~(1 << i);
@ -131,15 +131,14 @@ FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
ulonglong StartTime, EndTime, FilePos;
unsigned int Track, FrameFlags, FrameSize;
AVPacket TempPacket;
InitNullPacket(&TempPacket);
InitNullPacket(TempPacket);
while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) {
// Update progress
if (IC) {
if ((*IC)(ftello(MC.ST.fp), Filesize, ICPrivate)) {
snprintf(ErrorMsg, MsgSize, "Cancelled by user");
return NULL;
}
if ((*IC)(ftello(MC.ST.fp), Filesize, ICPrivate))
throw FFMS_Exception(FFMS_ERROR_CANCELLED, FFMS_ERROR_USER,
"Cancelled by user");
}
// Only create index entries for video for now to save space
@ -155,9 +154,10 @@ FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
(*TrackIndices)[Track].push_back(TFrameInfo::VideoFrameInfo(StartTime, RepeatPict, (FrameFlags & FRAME_KF) != 0, FilePos, FrameSize));
} else if (mkv_GetTrackInfo(MF, Track)->Type == TT_AUDIO && (IndexMask & (1 << Track))) {
(*TrackIndices)[Track].push_back(TFrameInfo::AudioFrameInfo(StartTime, AudioContexts[Track].CurrentSample, (FrameFlags & FRAME_KF) != 0, FilePos, FrameSize));
ReadFrame(FilePos, FrameSize, AudioContexts[Track].CS, MC, ErrorMsg, MsgSize);
int64_t StartSample = AudioContexts[Track].CurrentSample;
unsigned int CompressedFrameSize = FrameSize;
AVCodecContext *AudioCodecContext = AudioContexts[Track].CodecContext;
ReadFrame(FilePos, FrameSize, AudioContexts[Track].CS, MC);
TempPacket.data = MC.Buffer;
TempPacket.size = FrameSize;
if ((FrameFlags & FRAME_KF) != 0)
@ -169,13 +169,18 @@ FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10;
int Ret = avcodec_decode_audio3(AudioCodecContext, &DecodingBuffer[0], &dbsize, &TempPacket);
if (Ret < 0) {
if (IgnoreDecodeErrors) {
if (ErrorHandling == FFMS_IEH_ABORT) {
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING,
"Audio decoding error");
} else if (ErrorHandling == FFMS_IEH_CLEAR_TRACK) {
(*TrackIndices)[Track].clear();
IndexMask &= ~(1 << Track);
break;
} else {
snprintf(ErrorMsg, MsgSize, "Audio decoding error");
return NULL;
} else if (ErrorHandling == FFMS_IEH_STOP_TRACK) {
IndexMask &= ~(1 << Track);
break;
} else if (ErrorHandling == FFMS_IEH_IGNORE) {
break;
}
}
@ -188,8 +193,11 @@ FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) {
AudioContexts[Track].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels);
if (DumpMask & (1 << Track))
WriteAudio(AudioContexts[Track], TrackIndices.get(), Track, dbsize, ErrorMsg, MsgSize);
WriteAudio(AudioContexts[Track], TrackIndices.get(), Track, dbsize);
}
(*TrackIndices)[Track].push_back(TFrameInfo::AudioFrameInfo(StartTime, StartSample,
static_cast<unsigned int>(AudioContexts[Track].CurrentSample - StartSample), (FrameFlags & FRAME_KF) != 0, FilePos, CompressedFrameSize));
}
}
@ -207,7 +215,7 @@ FFMS_TrackType FFMatroskaIndexer::GetTrackType(int Track) {
const char *FFMatroskaIndexer::GetTrackCodec(int Track) {
if (Codec[Track])
return Codec[Track]->long_name;
return Codec[Track]->name;
else
return "Unsupported codec/Unknown codec name";
}

View file

@ -18,7 +18,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffvideosource.h"
#include "videosource.h"
void FFMatroskaVideo::Free(bool CloseCodec) {
if (CS)
@ -33,46 +35,39 @@ void FFMatroskaVideo::Free(bool CloseCodec) {
}
FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track,
FFIndex *Index, const char *PP,
int Threads, char *ErrorMsg, unsigned MsgSize)
: FFVideo(SourceFile, Index, ErrorMsg, MsgSize) {
FFMS_Index *Index, int Threads)
: Res(FFSourceResources<FFMS_VideoSource>(this)), FFMS_VideoSource(SourceFile, Index, Track) {
AVCodec *Codec = NULL;
CodecContext = NULL;
TrackInfo *TI = NULL;
CS = NULL;
PacketNumber = 0;
VideoTrack = Track;
Frames = (*Index)[VideoTrack];
if (Frames.size() == 0) {
snprintf(ErrorMsg, MsgSize, "Video track contains no frames");
throw ErrorMsg;
}
MC.ST.fp = ffms_fopen(SourceFile, "rb");
if (MC.ST.fp == NULL) {
snprintf(ErrorMsg, MsgSize, "Can't open '%s': %s", SourceFile, strerror(errno));
throw ErrorMsg;
}
if (MC.ST.fp == NULL)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Can't open '%1%': %2%") % SourceFile % strerror(errno));
setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage));
if (MF == NULL) {
fclose(MC.ST.fp);
snprintf(ErrorMsg, MsgSize, "Can't parse Matroska file: %s", ErrorMessage);
throw ErrorMsg;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Can't parse Matroska file: %1%") % ErrorMessage);
}
mkv_SetTrackMask(MF, ~(1 << VideoTrack));
TI = mkv_GetTrackInfo(MF, VideoTrack);
if (TI->CompEnabled) {
CS = cs_Create(MF, VideoTrack, ErrorMessage, sizeof(ErrorMessage));
if (CS == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Can't create decompressor: %s", ErrorMessage);
throw ErrorMsg;
throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_UNSUPPORTED,
boost::format("Can't create decompressor: %1%") % ErrorMessage);
}
}
@ -80,48 +75,35 @@ FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track,
CodecContext->thread_count = Threads;
Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate));
if (Codec == NULL) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Video codec not found");
throw ErrorMsg;
}
if (Codec == NULL)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Video codec not found");
InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext);
if (avcodec_open(CodecContext, Codec) < 0) {
Free(false);
snprintf(ErrorMsg, MsgSize, "Could not open video codec");
throw ErrorMsg;
}
if (avcodec_open(CodecContext, Codec) < 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Could not open video codec");
Res.CloseCodec(true);
// Always try to decode a frame to make sure all required parameters are known
int64_t Dummy;
if (DecodeNextFrame(&Dummy, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
DecodeNextFrame();
VP.Width = CodecContext->width;
VP.Height = CodecContext->height;;
VP.FPSDenominator = 1;
VP.FPSNumerator = 30;
VP.RFFDenominator = CodecContext->time_base.num;
VP.RFFNumerator = CodecContext->time_base.den;
VP.NumFrames = Frames.size();
VP.VPixelFormat = CodecContext->pix_fmt;
VP.TopFieldFirst = DecodeFrame->top_field_first;
VP.ColorSpace = CodecContext->colorspace;
VP.ColorRange = CodecContext->color_range;
VP.FirstTime = ((Frames.front().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
VP.LastTime = ((Frames.back().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
if (VP.Width <= 0 || VP.Height <= 0) {
Free(true);
snprintf(ErrorMsg, MsgSize, "Codec returned zero size video");
throw ErrorMsg;
}
if (InitPP(PP, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
if (CodecContext->width <= 0 || CodecContext->height <= 0)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
"Codec returned zero size video");
// Calculate the average framerate
if (Frames.size() >= 2) {
@ -131,10 +113,7 @@ FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track,
}
// Output the already decoded frame so it isn't wasted
if (!OutputFrame(DecodeFrame, ErrorMsg, MsgSize)) {
Free(true);
throw ErrorMsg;
}
OutputFrame(DecodeFrame);
// Set AR variables
VP.SARNum = TI->AV.Video.DisplayWidth * TI->AV.Video.PixelHeight;
@ -147,33 +126,33 @@ FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track,
VP.CropBottom = TI->AV.Video.CropB;
}
FFMatroskaVideo::~FFMatroskaVideo() {
Free(true);
}
int FFMatroskaVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) {
void FFMatroskaVideo::DecodeNextFrame() {
int FrameFinished = 0;
*AFirstStartTime = -1;
AVPacket Packet;
InitNullPacket(&Packet);
InitNullPacket(Packet);
ulonglong StartTime, EndTime, FilePos;
unsigned int Track, FrameFlags, FrameSize;
unsigned int FrameSize;
while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) {
if (*AFirstStartTime < 0)
*AFirstStartTime = StartTime;
if (ReadFrame(FilePos, FrameSize, CS, MC, ErrorMsg, MsgSize))
return 1;
while (PacketNumber < Frames.size()) {
// The additional indirection is because the packets are stored in
// presentation order and not decoding order, this is unnoticable
// in the other sources where less is done manually
const TFrameInfo &FI = Frames[Frames[PacketNumber].OriginalPos];
FrameSize = FI.FrameSize;
ReadFrame(FI.FilePos, FrameSize, CS, MC);
Packet.data = MC.Buffer;
Packet.size = FrameSize;
if (FrameFlags & FRAME_KF)
if (FI.KeyFrame)
Packet.flags = AV_PKT_FLAG_KEY;
else
Packet.flags = 0;
PacketNumber++;
if (CodecContext->codec_id == CODEC_ID_MPEG4 && IsNVOP(Packet))
goto Done;
avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet);
if (FrameFinished)
@ -183,7 +162,7 @@ int FFMatroskaVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, u
// Flush the last frames
if (CodecContext->has_b_frames) {
AVPacket NullPacket;
InitNullPacket(&NullPacket);
InitNullPacket(NullPacket);
avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket);
}
@ -191,40 +170,27 @@ int FFMatroskaVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, u
goto Error;
Error:
Done:
return 0;
Done:;
}
FFAVFrame *FFMatroskaVideo::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) {
// PPFrame always holds frame LastFrameNum even if no PP is applied
FFMS_Frame *FFMatroskaVideo::GetFrame(int n) {
GetFrameCheck(n);
if (LastFrameNum == n)
return OutputFrame(DecodeFrame, ErrorMsg, MsgSize);
return &LocalFrame;
bool HasSeeked = false;
if (n < CurrentFrame || Frames.FindClosestVideoKeyFrame(n) > CurrentFrame) {
mkv_Seek(MF, Frames[n].DTS, MKVF_SEEK_TO_PREV_KEYFRAME_STRICT);
int ClosestKF = Frames.FindClosestVideoKeyFrame(n);
if (CurrentFrame > n || ClosestKF > CurrentFrame + 10) {
PacketNumber = ClosestKF;
CurrentFrame = ClosestKF;
avcodec_flush_buffers(CodecContext);
HasSeeked = true;
}
do {
int64_t StartTime;
if (DecodeNextFrame(&StartTime, ErrorMsg, MsgSize))
return NULL;
if (HasSeeked) {
HasSeeked = false;
if (StartTime < 0 || (CurrentFrame = Frames.FrameFromDTS(StartTime)) < 0) {
snprintf(ErrorMsg, MsgSize, "Frame accurate seeking is not possible in this file");
return NULL;
}
}
DecodeNextFrame();
CurrentFrame++;
} while (CurrentFrame <= n);
LastFrameNum = n;
return OutputFrame(DecodeFrame, ErrorMsg, MsgSize);
return OutputFrame(DecodeFrame);
}

View file

@ -104,13 +104,13 @@ longlong StdIoGetFileSize(StdIoStream *st) {
void InitStdIoStream(StdIoStream *st) {
memset(st,0,sizeof(StdIoStream));
st->base.read = StdIoRead;
st->base.scan = StdIoScan;
st->base.getcachesize = StdIoGetCacheSize;
st->base.geterror = StdIoGetLastError;
st->base.memalloc = StdIoMalloc;
st->base.memrealloc = StdIoRealloc;
st->base.memfree = StdIoFree;
st->base.progress = StdIoProgress;
st->base.getfilesize = StdIoGetFileSize;
st->base.read = (int (*)(InputStream *,ulonglong,void *,int))StdIoRead;
st->base.scan = (longlong (*)(InputStream *,ulonglong,unsigned int))StdIoScan;
st->base.getcachesize = (unsigned int (*)(InputStream *))StdIoGetCacheSize;
st->base.geterror = (const char *(*)(InputStream *))StdIoGetLastError;
st->base.memalloc = (void *(*)(InputStream *,size_t))StdIoMalloc;
st->base.memrealloc = (void *(*)(InputStream *,void *,size_t))StdIoRealloc;
st->base.memfree = (void (*)(InputStream *,void *))StdIoFree;
st->base.progress = (int (*)(InputStream *,ulonglong,ulonglong))StdIoProgress;
st->base.getfilesize = (longlong (*)(InputStream *))StdIoGetFileSize;
}

View file

@ -46,6 +46,38 @@ extern const AVCodecTag ff_codec_wav_tags[];
extern int CPUFeatures;
FFMS_Exception::FFMS_Exception(int ErrorType, int SubType, const char *Message) : _ErrorType(ErrorType), _SubType(SubType), _Message(Message) {
}
FFMS_Exception::FFMS_Exception(int ErrorType, int SubType, const std::string &Message) : _ErrorType(ErrorType), _SubType(SubType), _Message(Message) {
}
FFMS_Exception::FFMS_Exception(int ErrorType, int SubType, const boost::format &Message) : _ErrorType(ErrorType), _SubType(SubType), _Message(Message.str()) {
}
FFMS_Exception::~FFMS_Exception() throw () {
}
const std::string &FFMS_Exception::GetErrorMessage() const {
return _Message;
}
int FFMS_Exception::CopyOut(FFMS_ErrorInfo *ErrorInfo) const {
if (ErrorInfo) {
ErrorInfo->ErrorType = _ErrorType;
ErrorInfo->SubType = _SubType;
if (ErrorInfo->BufferSize > 0) {
memset(ErrorInfo->Buffer, 0, ErrorInfo->BufferSize);
_Message.copy(ErrorInfo->Buffer, ErrorInfo->BufferSize - 1);
}
}
return (_ErrorType << 16) | _SubType;
}
int GetSWSCPUFlags() {
int Flags = 0;
@ -78,6 +110,16 @@ int GetPPCPUFlags() {
return Flags;
}
void ClearErrorInfo(FFMS_ErrorInfo *ErrorInfo) {
if (ErrorInfo) {
ErrorInfo->ErrorType = FFMS_ERROR_SUCCESS;
ErrorInfo->SubType = FFMS_ERROR_SUCCESS;
if (ErrorInfo->BufferSize > 0)
ErrorInfo->Buffer[0] = 0;
}
}
FFMS_TrackType HaaliTrackTypeToFFTrackType(int TT) {
switch (TT) {
case TT_VIDEO: return FFMS_TYPE_VIDEO; break;
@ -87,90 +129,92 @@ FFMS_TrackType HaaliTrackTypeToFFTrackType(int TT) {
}
}
int ReadFrame(uint64_t FilePos, unsigned int &FrameSize, CompressedStream *CS, MatroskaReaderContext &Context, char *ErrorMsg, unsigned MsgSize) {
void ReadFrame(uint64_t FilePos, unsigned int &FrameSize, CompressedStream *CS, MatroskaReaderContext &Context) {
if (CS) {
char CSBuffer[4096];
unsigned int DecompressedFrameSize = 0;
cs_NextFrame(CS, FilePos, FrameSize);
for (;;) {
int ReadBytes = cs_ReadData(CS, CSBuffer, sizeof(CSBuffer));
if (ReadBytes < 0) {
snprintf(ErrorMsg, MsgSize, "Error decompressing data: %s", cs_GetLastError(CS));
return 1;
}
int ReadBytes = cs_ReadData(CS, Context.CSBuffer, sizeof(Context.CSBuffer));
if (ReadBytes < 0)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Error decompressing data: %1%") % cs_GetLastError(CS));
if (ReadBytes == 0) {
FrameSize = DecompressedFrameSize;
return 0;
memset(Context.Buffer + DecompressedFrameSize, 0,
Context.BufferSize + FF_INPUT_BUFFER_PADDING_SIZE - DecompressedFrameSize);
return;
}
if (Context.BufferSize < DecompressedFrameSize + ReadBytes) {
Context.BufferSize = FrameSize;
Context.Buffer = (uint8_t *)realloc(Context.Buffer, Context.BufferSize + 16);
if (Context.Buffer == NULL) {
snprintf(ErrorMsg, MsgSize, "Out of memory");
return 2;
}
Context.BufferSize = DecompressedFrameSize + ReadBytes;
Context.Buffer = (uint8_t *)realloc(Context.Buffer, Context.BufferSize + FF_INPUT_BUFFER_PADDING_SIZE);
if (Context.Buffer == NULL)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
"Out of memory");
}
memcpy(Context.Buffer + DecompressedFrameSize, CSBuffer, ReadBytes);
memcpy(Context.Buffer + DecompressedFrameSize, Context.CSBuffer, ReadBytes);
DecompressedFrameSize += ReadBytes;
}
} else {
if (fseeko(Context.ST.fp, FilePos, SEEK_SET)) {
snprintf(ErrorMsg, MsgSize, "fseek(): %s", strerror(errno));
return 3;
}
if (fseeko(Context.ST.fp, FilePos, SEEK_SET))
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_SEEKING,
boost::format("fseek(): %1%") % strerror(errno));
if (Context.BufferSize < FrameSize) {
Context.BufferSize = FrameSize;
Context.Buffer = (uint8_t *)realloc(Context.Buffer, Context.BufferSize + 16);
if (Context.Buffer == NULL) {
snprintf(ErrorMsg, MsgSize, "Out of memory");
return 4;
}
if (Context.Buffer == NULL)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
"Out of memory");
}
size_t ReadBytes = fread(Context.Buffer, 1, FrameSize, Context.ST.fp);
if (ReadBytes != FrameSize) {
if (ReadBytes == 0) {
if (feof(Context.ST.fp)) {
snprintf(ErrorMsg, MsgSize, "Unexpected EOF while reading frame");
return 5;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
"Unexpected EOF while reading frame");
} else {
snprintf(ErrorMsg, MsgSize, "Error reading frame: %s", strerror(errno));
return 6;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_SEEKING,
boost::format("Error reading frame: %1%") % strerror(errno));
}
} else {
snprintf(ErrorMsg, MsgSize, "Short read while reading frame");
return 7;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
"Short read while reading frame");
}
snprintf(ErrorMsg, MsgSize, "Unknown read error");
return 8;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
"Unknown read error");
}
return 0;
return;
}
}
void InitNullPacket(AVPacket *pkt) {
av_init_packet(pkt);
pkt->data = NULL;
pkt->size = 0;
void InitNullPacket(AVPacket &pkt) {
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
}
void FillAP(FFAudioProperties &AP, AVCodecContext *CTX, FFTrack &Frames) {
bool IsNVOP(AVPacket &pkt) {
const uint8_t MPEG4NVOP[] = { 0x00, 0x00, 0x01, 0xB6 };
return pkt.size == 7 && !memcmp(pkt.data, MPEG4NVOP, 4);
}
void FillAP(FFMS_AudioProperties &AP, AVCodecContext *CTX, FFMS_Track &Frames) {
AP.SampleFormat = static_cast<FFMS_SampleFormat>(CTX->sample_fmt);
AP.BitsPerSample = av_get_bits_per_sample_format(CTX->sample_fmt);
if (CTX->sample_fmt == SAMPLE_FMT_S32)
if (CTX->sample_fmt == SAMPLE_FMT_S32 && CTX->bits_per_raw_sample)
AP.BitsPerSample = CTX->bits_per_raw_sample;
AP.Channels = CTX->channels;;
AP.ChannelLayout = CTX->channel_layout;
AP.SampleRate = CTX->sample_rate;
AP.NumSamples = (Frames.back()).SampleStart;
AP.NumSamples = (Frames.back()).SampleStart + (Frames.back()).SampleCount;
AP.FirstTime = ((Frames.front().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
AP.LastTime = ((Frames.back().DTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
}
@ -198,35 +242,37 @@ void vtCopy(VARIANT& vt,void *dest) {
}
}
#else
// used for matroska<->ffmpeg codec ID mapping to avoid Win32 dependency
typedef struct BITMAPINFOHEADER {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} BITMAPINFOHEADER;
#define MAKEFOURCC(ch0, ch1, ch2, ch3)\
((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) |\
((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 ))
#endif
CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC) {
CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC, unsigned int BitsPerSample) {
/* Look up native codecs */
for(int i = 0; ff_mkv_codec_tags[i].id != CODEC_ID_NONE; i++){
if(!strncmp(ff_mkv_codec_tags[i].str, Codec,
strlen(ff_mkv_codec_tags[i].str))) {
return ff_mkv_codec_tags[i].id;
// Uncompressed and exotic format fixup
// This list is incomplete
CodecID CID = ff_mkv_codec_tags[i].id;
switch (CID) {
case CODEC_ID_PCM_S16LE:
switch (BitsPerSample) {
case 8: CID = CODEC_ID_PCM_S8; break;
case 16: CID = CODEC_ID_PCM_S16LE; break;
case 24: CID = CODEC_ID_PCM_S24LE; break;
case 32: CID = CODEC_ID_PCM_S32LE; break;
}
break;
case CODEC_ID_PCM_S16BE:
switch (BitsPerSample) {
case 8: CID = CODEC_ID_PCM_S8; break;
case 16: CID = CODEC_ID_PCM_S16BE; break;
case 24: CID = CODEC_ID_PCM_S24BE; break;
case 32: CID = CODEC_ID_PCM_S32BE; break;
}
break;
}
return CID;
}
}
@ -234,7 +280,7 @@ CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC
const AVCodecTag *const tags[] = { ff_codec_bmp_tags, 0 };
if (!strcmp(Codec, "V_MS/VFW/FOURCC")) {
BITMAPINFOHEADER *b = reinterpret_cast<BITMAPINFOHEADER *>(CodecPrivate);
FFMS_BITMAPINFOHEADER *b = reinterpret_cast<FFMS_BITMAPINFOHEADER *>(CodecPrivate);
return av_codec_get_id(tags, b->biCompression);
}
@ -362,3 +408,60 @@ void ffms_fstream::open(const char *filename, std::ios_base::openmode mode) {
ffms_fstream::ffms_fstream(const char *filename, std::ios_base::openmode mode) {
open(filename, mode);
}
#ifdef HAALISOURCE
CComPtr<IMMContainer> HaaliOpenFile(const char *SourceFile, enum FFMS_Sources SourceMode) {
CComPtr<IMMContainer> pMMC;
CLSID clsid = HAALI_MPEG_PARSER;
if (SourceMode == FFMS_SOURCE_HAALIOGG)
clsid = HAALI_OGG_PARSER;
if (FAILED(pMMC.CoCreateInstance(clsid)))
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
"Can't create parser");
CComPtr<IMemAlloc> pMA;
if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc)))
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
"Can't create memory allocator");
CComPtr<IMMStream> pMS;
if (FAILED(pMS.CoCreateInstance(CLSID_DiskFile)))
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_ALLOCATION_FAILED,
"Can't create disk file reader");
WCHAR WSourceFile[2048];
ffms_mbstowcs(WSourceFile, SourceFile, 2000);
CComQIPtr<IMMStreamOpen> pMSO(pMS);
if (FAILED(pMSO->Open(WSourceFile)))
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
"Can't open file");
if (FAILED(pMMC->Open(pMS, 0, NULL, pMA))) {
if (SourceMode == FFMS_SOURCE_HAALIMPEG)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_INVALID_ARGUMENT,
"Can't parse file, most likely a transport stream not cut at packet boundaries");
else
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_INVALID_ARGUMENT,
"Can't parse file");
}
return pMMC;
}
#endif
void LAVFOpenFile(const char *SourceFile, AVFormatContext *&FormatContext) {
if (av_open_input_file(&FormatContext, SourceFile, NULL, 0, NULL) != 0)
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
boost::format("Couldn't open '%1'") % SourceFile);
if (av_find_stream_info(FormatContext) < 0) {
av_close_input_file(FormatContext);
FormatContext = NULL;
throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ,
"Couldn't find stream information");
}
}

View file

@ -23,7 +23,8 @@
#include <vector>
#include <fstream>
#include <stdio.h>
#include <cstdio>
#include <boost/format.hpp>
#include "ffms.h"
#include "matroskaparser.h"
@ -50,17 +51,73 @@ extern "C" {
# include "guids.h"
#endif
#define FFMS_GET_VECTOR_PTR(v) (((v).size() ? &(v)[0] : NULL))
const int64_t ffms_av_nopts_value = static_cast<int64_t>(1) << 63;
// used for matroska<->ffmpeg codec ID mapping to avoid Win32 dependency
typedef struct FFMS_BITMAPINFOHEADER {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} FFMS_BITMAPINFOHEADER;
class FFMS_Exception : public std::exception {
private:
std::string _Message;
int _ErrorType;
int _SubType;
public:
FFMS_Exception(int ErrorType, int SubType, const char *Message = "");
FFMS_Exception(int ErrorType, int SubType, const std::string &Message);
FFMS_Exception(int ErrorType, int SubType, const boost::format &Message);
~FFMS_Exception() throw ();
const std::string &GetErrorMessage() const;
int CopyOut(FFMS_ErrorInfo *ErrorInfo) const;
};
template<class T>
class FFSourceResources {
private:
T *_PrivClass;
bool _Enabled;
bool _Arg;
public:
FFSourceResources(T *Target) : _PrivClass(Target), _Enabled(true), _Arg(false) {
}
~FFSourceResources() {
if (_Enabled)
_PrivClass->Free(_Arg);
}
void SetEnabled(bool Enabled) {
_Enabled = Enabled;
}
void SetArg(bool Arg) {
_Arg = Arg;
}
void CloseCodec(bool Arg) {
_Arg = Arg;
}
};
struct MatroskaReaderContext {
public:
StdIoStream ST;
uint8_t *Buffer;
unsigned int BufferSize;
char CSBuffer[4096];
MatroskaReaderContext() {
InitStdIoStream(&ST);
@ -81,19 +138,25 @@ public:
int GetSWSCPUFlags();
int GetPPCPUFlags();
void ClearErrorInfo(FFMS_ErrorInfo *ErrorInfo);
FFMS_TrackType HaaliTrackTypeToFFTrackType(int TT);
int ReadFrame(uint64_t FilePos, unsigned int &FrameSize, CompressedStream *CS, MatroskaReaderContext &Context, char *ErrorMsg, unsigned MsgSize);
void ReadFrame(uint64_t FilePos, unsigned int &FrameSize, CompressedStream *CS, MatroskaReaderContext &Context);
bool AudioFMTIsFloat(SampleFormat FMT);
void InitNullPacket(AVPacket *pkt);
void FillAP(FFAudioProperties &AP, AVCodecContext *CTX, FFTrack &Frames);
void InitNullPacket(AVPacket &pkt);
bool IsNVOP(AVPacket &pkt);
void FillAP(FFMS_AudioProperties &AP, AVCodecContext *CTX, FFMS_Track &Frames);
#ifdef HAALISOURCE
unsigned vtSize(VARIANT &vt);
void vtCopy(VARIANT& vt,void *dest);
void InitializeCodecContextFromHaaliInfo(CComQIPtr<IPropertyBag> pBag, AVCodecContext *CodecContext);
#endif
void InitializeCodecContextFromMatroskaTrackInfo(TrackInfo *TI, AVCodecContext *CodecContext);
CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC = 0);
CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC = 0, unsigned int BitsPerSample = 0);
FILE *ffms_fopen(const char *filename, const char *mode);
size_t ffms_mbstowcs (wchar_t *wcstr, const char *mbstr, size_t max);
#ifdef HAALISOURCE
CComPtr<IMMContainer> HaaliOpenFile(const char *SourceFile, enum FFMS_Sources SourceMode);
#endif
void LAVFOpenFile(const char *SourceFile, AVFormatContext *&FormatContext);
#endif

View file

@ -18,24 +18,52 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffvideosource.h"
#include "videosource.h"
int FFVideo::InitPP(const char *PP, char *ErrorMsg, unsigned MsgSize) {
if (PP == NULL || !strcmp(PP, ""))
return 0;
void FFMS_VideoSource::GetFrameCheck(int n) {
if (n < 0 || n >= VP.NumFrames)
throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_INVALID_ARGUMENT,
"Out of bounds frame requested");
}
void FFMS_VideoSource::SetPP(const char *PP) {
if (PPMode)
pp_free_mode(PPMode);
PPMode = NULL;
if (PP != NULL && strcmp(PP, "")) {
PPMode = pp_get_mode_by_name_and_quality(PP, PP_QUALITY_MAX);
if (!PPMode) {
snprintf(ErrorMsg, MsgSize, "Invalid postprocesing settings");
return 1;
ResetPP();
throw FFMS_Exception(FFMS_ERROR_POSTPROCESSING, FFMS_ERROR_INVALID_ARGUMENT,
"Invalid postprocesing settings");
}
return 0;
}
int FFVideo::ReAdjustPP(PixelFormat VPixelFormat, int Width, int Height, char *ErrorMsg, unsigned MsgSize) {
ReAdjustPP(CodecContext->pix_fmt, CodecContext->width, CodecContext->height);
OutputFrame(DecodeFrame);
}
void FFMS_VideoSource::ResetPP() {
if (PPContext)
pp_free_context(PPContext);
PPContext = NULL;
if (PPMode)
pp_free_mode(PPMode);
PPMode = NULL;
OutputFrame(DecodeFrame);
}
void FFMS_VideoSource::ReAdjustPP(PixelFormat VPixelFormat, int Width, int Height) {
if (PPContext)
pp_free_context(PPContext);
PPContext = NULL;
if (!PPMode)
return 0;
return;
int Flags = GetPPCPUFlags();
@ -45,34 +73,30 @@ int FFVideo::ReAdjustPP(PixelFormat VPixelFormat, int Width, int Height, char *E
case PIX_FMT_YUV411P: Flags |= PP_FORMAT_411; break;
case PIX_FMT_YUV444P: Flags |= PP_FORMAT_444; break;
default:
snprintf(ErrorMsg, MsgSize, "Input format is not supported for postprocessing");
return 1;
ResetPP();
throw FFMS_Exception(FFMS_ERROR_POSTPROCESSING, FFMS_ERROR_UNSUPPORTED,
"The video does not have a colorspace suitable for postprocessing");
}
if (PPContext)
pp_free_context(PPContext);
PPContext = pp_get_context(Width, Height, Flags);
avpicture_free(&PPFrame);
avpicture_alloc(&PPFrame, VPixelFormat, Width, Height);
return 0;
}
static void CopyAVPictureFields(AVPicture &Picture, FFAVFrame &Dst) {
static void CopyAVPictureFields(AVPicture &Picture, FFMS_Frame &Dst) {
for (int i = 0; i < 4; i++) {
Dst.Data[i] = Picture.data[i];
Dst.Linesize[i] = Picture.linesize[i];
}
}
FFAVFrame *FFVideo::OutputFrame(AVFrame *Frame, char *ErrorMsg, unsigned MsgSize) {
FFMS_Frame *FFMS_VideoSource::OutputFrame(AVFrame *Frame) {
if (LastFrameWidth != CodecContext->width || LastFrameHeight != CodecContext->height || LastFramePixelFormat != CodecContext->pix_fmt) {
if (ReAdjustPP(CodecContext->pix_fmt, CodecContext->width, CodecContext->height, ErrorMsg, MsgSize))
return NULL;
ReAdjustPP(CodecContext->pix_fmt, CodecContext->width, CodecContext->height);
if (TargetHeight > 0 && TargetWidth > 0 && TargetPixelFormats != 0)
if (ReAdjustOutputFormat(TargetPixelFormats, TargetWidth, TargetHeight, TargetResizer, ErrorMsg, MsgSize))
return NULL;
ReAdjustOutputFormat(TargetPixelFormats, TargetWidth, TargetHeight, TargetResizer);
}
if (PPMode) {
@ -99,9 +123,9 @@ FFAVFrame *FFVideo::OutputFrame(AVFrame *Frame, char *ErrorMsg, unsigned MsgSize
LocalFrame.EncodedWidth = CodecContext->width;
LocalFrame.EncodedHeight = CodecContext->height;
LocalFrame.EncodedPixelFormat = CodecContext->pix_fmt;
LocalFrame.ScaledWidth = VP.Width;
LocalFrame.ScaledHeight = VP.Height;
LocalFrame.ConvertedPixelFormat = VP.VPixelFormat;
LocalFrame.ScaledWidth = TargetWidth;
LocalFrame.ScaledHeight = TargetHeight;
LocalFrame.ConvertedPixelFormat = OutputFormat;
LocalFrame.KeyFrame = Frame->key_frame;
LocalFrame.PictType = av_get_pict_type_char(Frame->pict_type);
LocalFrame.RepeatPict = Frame->repeat_pict;
@ -115,9 +139,22 @@ FFAVFrame *FFVideo::OutputFrame(AVFrame *Frame, char *ErrorMsg, unsigned MsgSize
return &LocalFrame;
}
FFVideo::FFVideo(const char *SourceFile, FFIndex *Index, char *ErrorMsg, unsigned MsgSize) {
if (Index->CompareFileSignature(SourceFile, ErrorMsg, MsgSize))
throw ErrorMsg;
FFMS_VideoSource::FFMS_VideoSource(const char *SourceFile, FFMS_Index *Index, int 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->at(Track).TT != FFMS_TYPE_VIDEO)
throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
"Not a video track");
if (Index[Track].size() == 0)
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");
memset(&VP, 0, sizeof(VP));
PPContext = NULL;
@ -133,6 +170,7 @@ FFVideo::FFVideo(const char *SourceFile, FFIndex *Index, char *ErrorMsg, unsigne
TargetWidth = -1;
TargetPixelFormats = 0;
TargetResizer = 0;
OutputFormat = PIX_FMT_NONE;
DecodeFrame = avcodec_alloc_frame();
// Dummy allocations so the unallocated case doesn't have to be handled later
@ -140,7 +178,7 @@ FFVideo::FFVideo(const char *SourceFile, FFIndex *Index, char *ErrorMsg, unsigne
avpicture_alloc(&SWSFrame, PIX_FMT_GRAY8, 16, 16);
}
FFVideo::~FFVideo() {
FFMS_VideoSource::~FFMS_VideoSource() {
if (PPMode)
pp_free_mode(PPMode);
@ -155,32 +193,33 @@ FFVideo::~FFVideo() {
av_freep(&DecodeFrame);
}
FFAVFrame *FFVideo::GetFrameByTime(double Time, char *ErrorMsg, unsigned MsgSize) {
FFMS_Frame *FFMS_VideoSource::GetFrameByTime(double Time) {
int Frame = Frames.ClosestFrameFromDTS(static_cast<int64_t>((Time * 1000 * Frames.TB.Den) / Frames.TB.Num));
return GetFrame(Frame, ErrorMsg, MsgSize);
return GetFrame(Frame);
}
int FFVideo::SetOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer, char *ErrorMsg, unsigned MsgSize) {
void FFMS_VideoSource::SetOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer) {
this->TargetWidth = Width;
this->TargetHeight = Height;
this->TargetPixelFormats = TargetFormats;
this->TargetResizer = Resizer;
return ReAdjustOutputFormat(TargetFormats, Width, Height, Resizer, ErrorMsg, MsgSize);
ReAdjustOutputFormat(TargetFormats, Width, Height, Resizer);
OutputFrame(DecodeFrame);
}
int FFVideo::ReAdjustOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer, char *ErrorMsg, unsigned MsgSize) {
void FFMS_VideoSource::ReAdjustOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer) {
if (SWS) {
sws_freeContext(SWS);
SWS = NULL;
}
int Loss;
PixelFormat OutputFormat = avcodec_find_best_pix_fmt(TargetFormats,
OutputFormat = avcodec_find_best_pix_fmt(TargetFormats,
CodecContext->pix_fmt, 1 /* Required to prevent pointless RGB32 => RGB24 conversion */, &Loss);
if (OutputFormat == PIX_FMT_NONE) {
ResetOutputFormat();
snprintf(ErrorMsg, MsgSize, "No suitable output format found");
return 1;
throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
"No suitable output format found");
}
if (CodecContext->pix_fmt != OutputFormat || Width != CodecContext->width || Height != CodecContext->height) {
@ -188,22 +227,16 @@ int FFVideo::ReAdjustOutputFormat(int64_t TargetFormats, int Width, int Height,
OutputFormat, GetSWSCPUFlags() | Resizer, NULL, NULL, NULL);
if (SWS == NULL) {
ResetOutputFormat();
snprintf(ErrorMsg, MsgSize, "Failed to allocate SWScale context");
return 1;
throw FFMS_Exception(FFMS_ERROR_SCALING, FFMS_ERROR_INVALID_ARGUMENT,
"Failed to allocate SWScale context");
}
}
VP.VPixelFormat = OutputFormat;
VP.Height = Height;
VP.Width = Width;
avpicture_free(&SWSFrame);
avpicture_alloc(&SWSFrame, OutputFormat, Width, Height);
return 0;
}
void FFVideo::ResetOutputFormat() {
void FFMS_VideoSource::ResetOutputFormat() {
if (SWS) {
sws_freeContext(SWS);
SWS = NULL;
@ -212,8 +245,7 @@ void FFVideo::ResetOutputFormat() {
TargetWidth = -1;
TargetHeight = -1;
TargetPixelFormats = 0;
OutputFormat = PIX_FMT_NONE;
VP.Height = CodecContext->height;
VP.Width = CodecContext->width;
VP.VPixelFormat = CodecContext->pix_fmt;
OutputFrame(DecodeFrame);
}

View file

@ -45,7 +45,8 @@ extern "C" {
# include "guids.h"
#endif
class FFVideo {
class FFMS_VideoSource {
friend class FFSourceResources<FFMS_VideoSource>;
private:
pp_context_t *PPContext;
pp_mode_t *PPMode;
@ -57,75 +58,83 @@ private:
int TargetWidth;
int64_t TargetPixelFormats;
int TargetResizer;
PixelFormat OutputFormat;
AVPicture PPFrame;
AVPicture SWSFrame;
protected:
FFVideoProperties VP;
FFAVFrame LocalFrame;
FFMS_VideoProperties VP;
FFMS_Frame LocalFrame;
AVFrame *DecodeFrame;
int LastFrameNum;
FFTrack Frames;
FFMS_Track Frames;
int VideoTrack;
int CurrentFrame;
AVCodecContext *CodecContext;
FFVideo(const char *SourceFile, FFIndex *Index, char *ErrorMsg, unsigned MsgSize);
int InitPP(const char *PP, char *ErrorMsg, unsigned MsgSize);
int ReAdjustPP(PixelFormat VPixelFormat, int Width, int Height, char *ErrorMsg, unsigned MsgSize);
FFAVFrame *OutputFrame(AVFrame *Frame, char *ErrorMsg, unsigned MsgSize);
FFMS_VideoSource(const char *SourceFile, FFMS_Index *Index, int Track);
void ReAdjustPP(PixelFormat VPixelFormat, int Width, int Height);
void ReAdjustOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer);
FFMS_Frame *OutputFrame(AVFrame *Frame);
virtual void Free(bool CloseCodec) = 0;
public:
virtual ~FFVideo();
const FFVideoProperties& GetFFVideoProperties() { return VP; }
FFTrack *GetFFTrack() { return &Frames; }
virtual FFAVFrame *GetFrame(int n, char *ErrorMsg, unsigned MsgSize) = 0;
FFAVFrame *GetFrameByTime(double Time, char *ErrorMsg, unsigned MsgSize);
int SetOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer, char *ErrorMsg, unsigned MsgSize);
int ReAdjustOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer, char *ErrorMsg, unsigned MsgSize);
virtual ~FFMS_VideoSource();
const FFMS_VideoProperties& GetVideoProperties() { return VP; }
FFMS_Track *GetTrack() { return &Frames; }
virtual FFMS_Frame *GetFrame(int n) = 0;
void GetFrameCheck(int n);
FFMS_Frame *GetFrameByTime(double Time);
void SetPP(const char *PP);
void ResetPP();
void SetOutputFormat(int64_t TargetFormats, int Width, int Height, int Resizer);
void ResetOutputFormat();
};
class FFLAVFVideo : public FFVideo {
class FFLAVFVideo : public FFMS_VideoSource {
private:
AVFormatContext *FormatContext;
int SeekMode;
FFSourceResources<FFMS_VideoSource> Res;
void DecodeNextFrame(int64_t *DTS);
protected:
void Free(bool CloseCodec);
int DecodeNextFrame(int64_t *DTS, char *ErrorMsg, unsigned MsgSize);
public:
FFLAVFVideo(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize);
~FFLAVFVideo();
FFAVFrame *GetFrame(int n, char *ErrorMsg, unsigned MsgSize);
FFLAVFVideo(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode);
FFMS_Frame *GetFrame(int n);
};
class FFMatroskaVideo : public FFVideo {
class FFMatroskaVideo : public FFMS_VideoSource {
private:
MatroskaFile *MF;
MatroskaReaderContext MC;
CompressedStream *CS;
char ErrorMessage[256];
FFSourceResources<FFMS_VideoSource> Res;
size_t PacketNumber;
void DecodeNextFrame();
protected:
void Free(bool CloseCodec);
int DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize);
public:
FFMatroskaVideo(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, char *ErrorMsg, unsigned MsgSize);
~FFMatroskaVideo();
FFAVFrame *GetFrame(int n, char *ErrorMsg, unsigned MsgSize);
FFMatroskaVideo(const char *SourceFile, int Track, FFMS_Index *Index, int Threads);
FFMS_Frame *GetFrame(int n);
};
#ifdef HAALISOURCE
class FFHaaliVideo : public FFVideo {
class FFHaaliVideo : public FFMS_VideoSource {
private:
CComPtr<IMMContainer> pMMC;
std::vector<uint8_t> CodecPrivate;
AVBitStreamFilterContext *BitStreamFilter;
FFSourceResources<FFMS_VideoSource> Res;
void DecodeNextFrame(int64_t *AFirstStartTime);
protected:
void Free(bool CloseCodec);
int DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize);
public:
FFHaaliVideo(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SourceMode, char *ErrorMsg, unsigned MsgSize);
~FFHaaliVideo();
FFAVFrame *GetFrame(int n, char *ErrorMsg, unsigned MsgSize);
FFHaaliVideo(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, enum FFMS_Sources SourceMode);
FFMS_Frame *GetFrame(int n);
};
#endif // HAALISOURCE