FileHandle::FileHandle(const char *filename, const char *mode, int error_source, int error_cause) : avio(ffms_fopen(filename, mode)) , filename(filename) , error_source(error_source) , error_cause(error_cause) { if (!avio) throw FFMS_Exception(error_source, FFMS_ERROR_NO_FILE, "Failed to open '" + this->filename + "'"); }
FFMatroskaAudio::FFMatroskaAudio(const char *SourceFile, int Track, FFMS_Index &Index, int DelayMode) : FFMS_AudioSource(SourceFile, Index, Track) , TI(NULL) { if (!(MC.ST.fp = ffms_fopen(SourceFile, "rb"))) throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, std::string("Can't open '") + SourceFile + "': " + strerror(errno)); setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE); if (!(MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage)))) throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, std::string("Can't parse Matroska file: ") + ErrorMessage); TI = mkv_GetTrackInfo(MF, Track); assert(TI); if (TI->CompEnabled) TCC.reset(new TrackCompressionContext(MF, TI, Track)); CodecContext.reset(avcodec_alloc_context3(NULL), DeleteMatroskaCodecContext); assert(CodecContext); AVCodec *Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate, 0, TI->AV.Audio.BitDepth)); if (!Codec) { mkv_Close(MF); throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Audio codec not found"); } InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext); if (avcodec_open2(CodecContext, Codec, NULL) < 0) { mkv_Close(MF); throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Could not open audio codec"); } Init(Index, DelayMode); }
FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track, FFMS_Index &Index, int Threads) : FFMS_VideoSource(SourceFile, Index, Track, Threads) , MF(0) , Res(FFSourceResources<FFMS_VideoSource>(this)) , PacketNumber(0) { AVCodec *Codec = NULL; TrackInfo *TI = NULL; MC.ST.fp = ffms_fopen(SourceFile, "rb"); if (MC.ST.fp == NULL) { std::ostringstream buf; buf << "Can't open '" << SourceFile << "': " << strerror(errno); throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str()); } setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE); MF = mkv_OpenEx(&MC.ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage)); if (MF == NULL) { std::ostringstream buf; buf << "Can't parse Matroska file: " << ErrorMessage; throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_FILE_READ, buf.str()); } TI = mkv_GetTrackInfo(MF, VideoTrack); if (TI->CompEnabled) TCC.reset(new TrackCompressionContext(MF, TI, VideoTrack)); CodecContext = avcodec_alloc_context3(NULL); CodecContext->thread_count = DecodingThreads; Codec = avcodec_find_decoder(MatroskaToFFCodecID(TI->CodecID, TI->CodecPrivate)); if (Codec == NULL) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Video codec not found"); InitializeCodecContextFromMatroskaTrackInfo(TI, CodecContext); if (avcodec_open2(CodecContext, Codec, NULL) < 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 DecodeNextFrame(); VP.FPSDenominator = 1; VP.FPSNumerator = 30; // Calculate the average framerate if (Frames.size() >= 2) { double PTSDiff = (double)(Frames.back().PTS - Frames.front().PTS); // Dividing by 1000 caused too much information to be lost, when CorrectNTSCRationalFramerate runs there was a possibility // of it outputting the wrong framerate. We still divide by 100 to protect against the possibility of overflows. VP.FPSDenominator = (unsigned int)(PTSDiff * mkv_TruncFloat(TI->TimecodeScale) / (double)100 / (double)(Frames.size() - 1) + 0.5); VP.FPSNumerator = 10000000; } // Set the video properties from the codec context SetVideoProperties(); // Output the already decoded frame so it isn't wasted OutputFrame(DecodeFrame); // Set AR variables VP.SARNum = TI->AV.Video.DisplayWidth * TI->AV.Video.PixelHeight; VP.SARDen = TI->AV.Video.DisplayHeight * TI->AV.Video.PixelWidth; // Set crop variables VP.CropLeft = TI->AV.Video.CropL; VP.CropRight = TI->AV.Video.CropR; VP.CropTop = TI->AV.Video.CropT; VP.CropBottom = TI->AV.Video.CropB; }