void FFMS_VideoSource::SetVideoProperties() { VP.RFFDenominator = CodecContext->time_base.num; VP.RFFNumerator = CodecContext->time_base.den; if (CodecContext->codec_id == FFMS_ID(H264)) { if (VP.RFFNumerator & 1) VP.RFFDenominator *= 2; else VP.RFFNumerator /= 2; } VP.NumFrames = Frames.VisibleFrameCount(); VP.TopFieldFirst = DecodeFrame->top_field_first; VP.ColorSpace = CodecContext->colorspace; VP.ColorRange = CodecContext->color_range; // these pixfmt's are deprecated but still used if ( CodecContext->pix_fmt == PIX_FMT_YUVJ420P || CodecContext->pix_fmt == PIX_FMT_YUVJ422P || CodecContext->pix_fmt == PIX_FMT_YUVJ444P ) VP.ColorRange = AVCOL_RANGE_JPEG; VP.FirstTime = ((Frames.front().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000; VP.LastTime = ((Frames.back().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000; if (CodecContext->width <= 0 || CodecContext->height <= 0) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Codec returned zero size video"); // attempt to correct framerate to the proper NTSC fraction, if applicable CorrectNTSCRationalFramerate(&VP.FPSNumerator, &VP.FPSDenominator); // correct the timebase, if necessary CorrectTimebase(&VP, &Frames.TB); // Set AR variables VP.SARNum = CodecContext->sample_aspect_ratio.num; VP.SARDen = CodecContext->sample_aspect_ratio.den; // Set input and output formats now that we have a CodecContext DetectInputFormat(); OutputFormat = InputFormat; OutputColorSpace = InputColorSpace; OutputColorRange = InputColorRange; }
void FlushBuffers(AVCodecContext *CodecContext) { if (CodecContext->codec->flush) avcodec_flush_buffers(CodecContext); else { // If the codec doesn't have flush(), it might not need it... or it // might need it and just not implement it as in the case of VC-1, so // close and reopen the codec const AVCodec *codec = CodecContext->codec; // Only flush blacklisted codecs, closing and reopening breaks far too // many decoders to always do as a fallback!!! // Further notes: VC1 does have a flush in recent versions so // maybe just remove all this junk unless more formats are found that // need it if (codec->id == FFMS_ID(VC1)) { avcodec_close(CodecContext); // Whether or not codec is const varies between versions if (avcodec_open2(CodecContext, const_cast<AVCodec *>(codec), nullptr) < 0) throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_CODEC, "Couldn't re-open codec."); } } }
FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track, FFMS_Index &Index, int Threads, FFMS_Sources SourceMode) : Res(FFSourceResources<FFMS_VideoSource>(this)), FFMS_VideoSource(SourceFile, Index, Track, Threads) { BitStreamFilter = NULL; pMMC = HaaliOpenFile(SourceFile, SourceMode); CComPtr<IEnumUnknown> pEU; if (!SUCCEEDED(pMMC->EnumTracks(&pEU))) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Failed to enumerate tracks"); CComPtr<IUnknown> pU; int CurrentTrack = -1; while (pEU->Next(1, &pU, NULL) == S_OK && ++CurrentTrack != Track) pU = NULL; CComQIPtr<IPropertyBag> pBag = pU; if (CurrentTrack != Track || !pBag) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Failed to find track"); HCodecContext = InitializeCodecContextFromHaaliInfo(pBag); CodecContext = HCodecContext; const AVCodec *Codec = NULL; std::swap(Codec, CodecContext->codec); if (avcodec_open2(CodecContext, Codec, NULL) < 0) throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC, "Could not open video codec"); CodecContext->thread_count = DecodingThreads; if (CodecContext->codec->id == FFMS_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; DecodeNextFrame(&Dummy); VP.FPSDenominator = 1; VP.FPSNumerator = 30; // Calculate the average framerate if (Frames.size() >= 2) { double PTSDiff = (double)(Frames.back().PTS - Frames.front().PTS); VP.FPSDenominator = (unsigned int)(PTSDiff / (double)1000 / (double)(Frames.size() - 1) + 0.5); VP.FPSNumerator = 1000000; } // Set the video properties from the codec context SetVideoProperties(); // Output the already decoded frame so it isn't wasted OutputFrame(DecodeFrame); // Set AR variables CComVariant pV; USHORT Num = 0, Den = 0; pV.Clear(); if (SUCCEEDED(pBag->Read(L"Video.DisplayWidth", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4))) Num = pV.uiVal; pV.Clear(); if (SUCCEEDED(pBag->Read(L"Video.DisplayHeight", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_UI4))) Den = pV.uiVal; if (Num && Den) { VP.SARNum = LocalFrame.EncodedHeight * Num; VP.SARDen = LocalFrame.EncodedWidth * Den; } }
FFMS_CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate, unsigned int FourCC, unsigned int BitsPerSample) { /* Look up native codecs */ for (int i = 0; mkv_codec_tags[i].id != FFMS_ID(NONE); i++){ if (!strncmp(mkv_codec_tags[i].str, Codec, strlen(mkv_codec_tags[i].str))) { // Uncompressed and exotic format fixup // This list is incomplete FFMS_CodecID CID = mkv_codec_tags[i].id; switch (CID) { case FFMS_ID(PCM_S16LE): switch (BitsPerSample) { case 8: CID = FFMS_ID(PCM_S8); break; case 16: CID = FFMS_ID(PCM_S16LE); break; case 24: CID = FFMS_ID(PCM_S24LE); break; case 32: CID = FFMS_ID(PCM_S32LE); break; } break; case FFMS_ID(PCM_S16BE): switch (BitsPerSample) { case 8: CID = FFMS_ID(PCM_S8); break; case 16: CID = FFMS_ID(PCM_S16BE); break; case 24: CID = FFMS_ID(PCM_S24BE); break; case 32: CID = FFMS_ID(PCM_S32BE); break; } break; default: break; } return CID; } } /* Video codecs for "avi in mkv" mode */ const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), 0 }; if (!strcmp(Codec, "V_MS/VFW/FOURCC")) { FFMS_BITMAPINFOHEADER *b = reinterpret_cast<FFMS_BITMAPINFOHEADER *>(CodecPrivate); return av_codec_get_id(tags, b->biCompression); } if (!strcmp(Codec, "V_FOURCC")) { return av_codec_get_id(tags, FourCC); } // FIXME /* Audio codecs for "acm in mkv" mode */ //#include "Mmreg.h" //((WAVEFORMATEX *)TI->CodecPrivate)->wFormatTag /* Fixup for uncompressed video formats */ /* Fixup for uncompressed audio formats */ return FFMS_ID(NONE); }
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "codectype.h" #include "matroskaparser.h" #include "utils.h" typedef struct CodecTags { char str[20]; FFMS_CodecID id; } CodecTags; static const CodecTags mkv_codec_tags[] = { {"A_AAC" , FFMS_ID(AAC)}, {"A_AC3" , FFMS_ID(AC3)}, {"A_DTS" , FFMS_ID(DTS)}, {"A_EAC3" , FFMS_ID(EAC3)}, {"A_FLAC" , FFMS_ID(FLAC)}, {"A_MLP" , FFMS_ID(MLP)}, {"A_MPEG/L2" , FFMS_ID(MP2)}, {"A_MPEG/L1" , FFMS_ID(MP2)}, {"A_MPEG/L3" , FFMS_ID(MP3)}, #if VERSION_CHECK(LIBAVCODEC_VERSION_INT, >=, 54, 29, 0, 54, 60, 100) {"A_OPUS" , FFMS_ID(OPUS)}, {"A_OPUS/EXPERIMENTAL" , FFMS_ID(OPUS)}, /* Pre-final ID, for compatibility */ #endif {"A_PCM/FLOAT/IEEE" , FFMS_ID(PCM_F32LE)}, {"A_PCM/FLOAT/IEEE" , FFMS_ID(PCM_F64LE)}, {"A_PCM/INT/BIG" , FFMS_ID(PCM_S16BE)},