michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "MediaTaskQueue.h" michael@0: #include "mp4_demuxer/mp4_demuxer.h" michael@0: #include "FFmpegRuntimeLinker.h" michael@0: michael@0: #include "FFmpegDataDecoder.h" michael@0: michael@0: namespace mozilla michael@0: { michael@0: michael@0: bool FFmpegDataDecoder::sFFmpegInitDone = false; michael@0: michael@0: FFmpegDataDecoder::FFmpegDataDecoder(MediaTaskQueue* aTaskQueue, michael@0: AVCodecID aCodecID) michael@0: : mTaskQueue(aTaskQueue), mCodecID(aCodecID) michael@0: { michael@0: MOZ_COUNT_CTOR(FFmpegDataDecoder); michael@0: } michael@0: michael@0: FFmpegDataDecoder::~FFmpegDataDecoder() { michael@0: MOZ_COUNT_DTOR(FFmpegDataDecoder); michael@0: } michael@0: michael@0: /** michael@0: * FFmpeg calls back to this function with a list of pixel formats it supports. michael@0: * We choose a pixel format that we support and return it. michael@0: * For now, we just look for YUV420P as it is the only non-HW accelerated format michael@0: * supported by FFmpeg's H264 decoder. michael@0: */ michael@0: static PixelFormat michael@0: ChoosePixelFormat(AVCodecContext* aCodecContext, const PixelFormat* aFormats) michael@0: { michael@0: FFMPEG_LOG("Choosing FFmpeg pixel format for video decoding."); michael@0: for (; *aFormats > -1; aFormats++) { michael@0: if (*aFormats == PIX_FMT_YUV420P) { michael@0: FFMPEG_LOG("Requesting pixel format YUV420P."); michael@0: return PIX_FMT_YUV420P; michael@0: } michael@0: } michael@0: michael@0: NS_WARNING("FFmpeg does not share any supported pixel formats."); michael@0: return PIX_FMT_NONE; michael@0: } michael@0: michael@0: nsresult michael@0: FFmpegDataDecoder::Init() michael@0: { michael@0: FFMPEG_LOG("Initialising FFmpeg decoder."); michael@0: michael@0: if (!FFmpegRuntimeLinker::Link()) { michael@0: NS_WARNING("Failed to link FFmpeg shared libraries."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!sFFmpegInitDone) { michael@0: av_register_all(); michael@0: #ifdef DEBUG michael@0: av_log_set_level(AV_LOG_DEBUG); michael@0: #endif michael@0: sFFmpegInitDone = true; michael@0: } michael@0: michael@0: AVCodec* codec = avcodec_find_decoder(mCodecID); michael@0: if (!codec) { michael@0: NS_WARNING("Couldn't find ffmpeg decoder"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (avcodec_get_context_defaults3(&mCodecContext, codec) < 0) { michael@0: NS_WARNING("Couldn't init ffmpeg context"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mCodecContext.opaque = this; michael@0: michael@0: // FFmpeg takes this as a suggestion for what format to use for audio samples. michael@0: mCodecContext.request_sample_fmt = AV_SAMPLE_FMT_FLT; michael@0: michael@0: // FFmpeg will call back to this to negotiate a video pixel format. michael@0: mCodecContext.get_format = ChoosePixelFormat; michael@0: michael@0: AVDictionary* opts = nullptr; michael@0: if (avcodec_open2(&mCodecContext, codec, &opts) < 0) { michael@0: NS_WARNING("Couldn't initialise ffmpeg decoder"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (mCodecContext.codec_type == AVMEDIA_TYPE_AUDIO && michael@0: mCodecContext.sample_fmt != AV_SAMPLE_FMT_FLT && michael@0: mCodecContext.sample_fmt != AV_SAMPLE_FMT_FLTP) { michael@0: NS_WARNING("FFmpeg AAC decoder outputs unsupported audio format."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: FFMPEG_LOG("FFmpeg init successful."); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: FFmpegDataDecoder::Flush() michael@0: { michael@0: mTaskQueue->Flush(); michael@0: avcodec_flush_buffers(&mCodecContext); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: FFmpegDataDecoder::Shutdown() michael@0: { michael@0: if (sFFmpegInitDone) { michael@0: avcodec_close(&mCodecContext); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // namespace mozilla