void FFmpegVideoDecoder<LIBAV_VER>::InitCodecContext() { mCodecContext->width = mInfo.mImage.width; mCodecContext->height = mInfo.mImage.height; // We use the same logic as libvpx in determining the number of threads to use // so that we end up behaving in the same fashion when using ffmpeg as // we would otherwise cause various crashes (see bug 1236167) int decode_threads = 1; if (mInfo.mDisplay.width >= 2048) { decode_threads = 8; } else if (mInfo.mDisplay.width >= 1024) { decode_threads = 4; } else if (mInfo.mDisplay.width >= 320) { decode_threads = 2; } decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors() - 1); decode_threads = std::max(decode_threads, 1); mCodecContext->thread_count = decode_threads; if (decode_threads > 1) { mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME; } // FFmpeg will call back to this to negotiate a video pixel format. mCodecContext->get_format = ChoosePixelFormat; mCodecParser = mLib->av_parser_init(mCodecID); if (mCodecParser) { mCodecParser->flags |= PARSER_FLAG_COMPLETE_FRAMES; } }
nsresult SoftwareWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) { int decode_threads = 2; //Default to 2 threads for small sizes or VP8 vpx_codec_iface_t* dx = nullptr; switch(mReader->GetVideoCodec()) { case NESTEGG_CODEC_VP8: dx = vpx_codec_vp8_dx(); break; case NESTEGG_CODEC_VP9: dx = vpx_codec_vp9_dx(); if (aWidth >= 2048) { decode_threads = 8; } else if (aWidth >= 1024) { decode_threads = 4; } break; } // Never exceed the number of system cores! decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors()); vpx_codec_dec_cfg_t config; config.threads = decode_threads; config.w = aWidth; config.h = aHeight; if (!dx || vpx_codec_dec_init(&mVPX, dx, &config, 0)) { return NS_ERROR_FAILURE; } return NS_OK; }
nsresult FFmpegDataDecoder<LIBAV_VER>::Init() { FFMPEG_LOG("Initialising FFmpeg decoder."); if (!sFFmpegInitDone) { av_register_all(); #ifdef DEBUG av_log_set_level(AV_LOG_DEBUG); #endif sFFmpegInitDone = true; } AVCodec* codec = avcodec_find_decoder(mCodecID); if (!codec) { NS_WARNING("Couldn't find ffmpeg decoder"); return NS_ERROR_FAILURE; } if (!(mCodecContext = avcodec_alloc_context3(codec))) { NS_WARNING("Couldn't init ffmpeg context"); return NS_ERROR_FAILURE; } mCodecContext->opaque = this; // FFmpeg takes this as a suggestion for what format to use for audio samples. mCodecContext->request_sample_fmt = AV_SAMPLE_FMT_FLT; // FFmpeg will call back to this to negotiate a video pixel format. mCodecContext->get_format = ChoosePixelFormat; mCodecContext->thread_count = PR_GetNumberOfProcessors(); mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME; mCodecContext->thread_safe_callbacks = false; mCodecContext->extradata_size = mExtraData.length(); for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) { mExtraData.append(0); } mCodecContext->extradata = mExtraData.begin(); if (avcodec_open2(mCodecContext, codec, nullptr) < 0) { NS_WARNING("Couldn't initialise ffmpeg decoder"); return NS_ERROR_FAILURE; } if (mCodecContext->codec_type == AVMEDIA_TYPE_AUDIO && mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLTP) { NS_WARNING("FFmpeg AAC decoder outputs unsupported audio format."); return NS_ERROR_FAILURE; } FFMPEG_LOG("FFmpeg init successful."); return NS_OK; }
/* static */ int WMFDecoderModule::GetNumDecoderThreads() { int32_t numCores = PR_GetNumberOfProcessors(); // If we have more than 4 cores, let the decoder decide how many threads. // On an 8 core machine, WMF chooses 4 decoder threads const int WMF_DECODER_DEFAULT = -1; int32_t prefThreadCount = MediaPrefs::PDMWMFThreadCount(); if (prefThreadCount != WMF_DECODER_DEFAULT) { return std::max(prefThreadCount, 1); } else if (numCores > 4) { return WMF_DECODER_DEFAULT; } return std::max(numCores - 1, 1); }
static void SetNumOfDecoderThreads() { MOZ_ASSERT(NS_IsMainThread(), "Preferences can only be read on main thread"); int32_t numCores = PR_GetNumberOfProcessors(); // If we have more than 4 cores, let the decoder decide how many threads. // On an 8 core machine, WMF chooses 4 decoder threads const int WMF_DECODER_DEFAULT = -1; int32_t prefThreadCount = Preferences::GetInt("media.wmf.decoder.thread-count", -1); if (prefThreadCount != WMF_DECODER_DEFAULT) { sNumDecoderThreads = std::max(prefThreadCount, 1); } else if (numCores > 4) { sNumDecoderThreads = WMF_DECODER_DEFAULT; } else { sNumDecoderThreads = std::max(numCores - 1, 1); } }
nsresult EMEH264Decoder::GmpInit() { MOZ_ASSERT(IsOnGMPThread()); nsTArray<nsCString> tags; tags.AppendElement(NS_LITERAL_CSTRING("h264")); tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem())); nsresult rv = mMPS->GetGMPVideoDecoder(&tags, mProxy->GetOrigin(), &mHost, &mGMP); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(mHost && mGMP); GMPVideoCodec codec; memset(&codec, 0, sizeof(codec)); codec.mGMPApiVersion = kGMPVersion33; codec.mCodecType = kGMPVideoCodecH264; codec.mWidth = mConfig.display_width; codec.mHeight = mConfig.display_height; nsTArray<uint8_t> codecSpecific; codecSpecific.AppendElement(0); // mPacketizationMode. codecSpecific.AppendElements(mConfig.extra_data.begin(), mConfig.extra_data.length()); rv = mGMP->InitDecode(codec, codecSpecific, this, PR_GetNumberOfProcessors()); NS_ENSURE_SUCCESS(rv, rv); mVideoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height); mVideoInfo.mHasVideo = true; mPictureRegion = nsIntRect(0, 0, mConfig.display_width, mConfig.display_height); return NS_OK; }
PRIntn main(PRIntn argc, char **argv) { PRStatus rv; PRSysInfo cmd; PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); char *info = (char*)PR_Calloc(SYS_INFO_BUFFER_LENGTH, 1); for (cmd = PR_SI_HOSTNAME; cmd <= PR_SI_ARCHITECTURE; Incr(&cmd)) { rv = PR_GetSystemInfo(cmd, info, SYS_INFO_BUFFER_LENGTH); if (PR_SUCCESS == rv) PR_fprintf(output, "%s: %s\n", tag[cmd], info); else PL_FPrintError(output, tag[cmd]); } PR_DELETE(info); PR_fprintf(output, "Host page size is %d\n", PR_GetPageSize()); PR_fprintf(output, "Page shift is %d\n", PR_GetPageShift()); PR_fprintf(output, "Number of processors is: %d\n", PR_GetNumberOfProcessors()); return 0; } /* main */
void GMPVideoDecoder::GMPInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) { MOZ_ASSERT(aHost && aGMP); GMPVideoCodec codec; memset(&codec, 0, sizeof(codec)); codec.mGMPApiVersion = kGMPVersion33; codec.mCodecType = kGMPVideoCodecH264; codec.mWidth = mConfig.mDisplay.width; codec.mHeight = mConfig.mDisplay.height; nsTArray<uint8_t> codecSpecific; codecSpecific.AppendElement(0); // mPacketizationMode. codecSpecific.AppendElements(mConfig.mExtraData->Elements(), mConfig.mExtraData->Length()); nsresult rv = aGMP->InitDecode(codec, codecSpecific, mAdapter, PR_GetNumberOfProcessors()); if (NS_SUCCEEDED(rv)) { mGMP = aGMP; mHost = aHost; // GMP implementations have interpreted the meaning of GMP_BufferLength32 // differently. The OpenH264 GMP expects GMP_BufferLength32 to behave as // specified in the GMP API, where each buffer is prefixed by a 32-bit // host-endian buffer length that includes the size of the buffer length // field. Other existing GMPs currently expect GMP_BufferLength32 (when // combined with kGMPVideoCodecH264) to mean "like AVCC but restricted to // 4-byte NAL lengths" (i.e. buffer lengths are specified in big-endian // and do not include the length of the buffer length field. mConvertNALUnitLengths = mGMP->GetDisplayName().EqualsLiteral("gmpopenh264"); } }
void GMPVideoDecoder::GMPInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) { MOZ_ASSERT(IsOnGMPThread()); if (!aGMP) { mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); return; } MOZ_ASSERT(aHost); if (mInitPromise.IsEmpty()) { // GMP must have been shutdown while we were waiting for Init operation // to complete. aGMP->Close(); return; } bool isOpenH264 = aGMP->GetDisplayName().EqualsLiteral("gmpopenh264"); GMPVideoCodec codec; memset(&codec, 0, sizeof(codec)); codec.mGMPApiVersion = kGMPVersion33; nsTArray<uint8_t> codecSpecific; if (MP4Decoder::IsH264(mConfig.mMimeType)) { codec.mCodecType = kGMPVideoCodecH264; codecSpecific.AppendElement(0); // mPacketizationMode. codecSpecific.AppendElements(mConfig.mExtraData->Elements(), mConfig.mExtraData->Length()); // OpenH264 expects pseudo-AVCC, but others must be passed // AnnexB for H264. mConvertToAnnexB = !isOpenH264; } else if (VPXDecoder::IsVP8(mConfig.mMimeType)) { codec.mCodecType = kGMPVideoCodecVP8; } else if (VPXDecoder::IsVP9(mConfig.mMimeType)) { codec.mCodecType = kGMPVideoCodecVP9; } else { // Unrecognized mime type aGMP->Close(); mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); return; } codec.mWidth = mConfig.mImage.width; codec.mHeight = mConfig.mImage.height; nsresult rv = aGMP->InitDecode(codec, codecSpecific, this, PR_GetNumberOfProcessors()); if (NS_FAILED(rv)) { aGMP->Close(); mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); return; } mGMP = aGMP; mHost = aHost; // GMP implementations have interpreted the meaning of GMP_BufferLength32 // differently. The OpenH264 GMP expects GMP_BufferLength32 to behave as // specified in the GMP API, where each buffer is prefixed by a 32-bit // host-endian buffer length that includes the size of the buffer length // field. Other existing GMPs currently expect GMP_BufferLength32 (when // combined with kGMPVideoCodecH264) to mean "like AVCC but restricted to // 4-byte NAL lengths" (i.e. buffer lengths are specified in big-endian // and do not include the length of the buffer length field. mConvertNALUnitLengths = isOpenH264; mInitPromise.Resolve(TrackInfo::kVideoTrack, __func__); }
nsresult FFmpegDataDecoder<LIBAV_VER>::InitDecoder() { FFMPEG_LOG("Initialising FFmpeg decoder."); AVCodec* codec = FindAVCodec(mCodecID); if (!codec) { NS_WARNING("Couldn't find ffmpeg decoder"); return NS_ERROR_FAILURE; } StaticMutexAutoLock mon(sMonitor); if (!(mCodecContext = avcodec_alloc_context3(codec))) { NS_WARNING("Couldn't init ffmpeg context"); return NS_ERROR_FAILURE; } mCodecContext->opaque = this; // FFmpeg takes this as a suggestion for what format to use for audio samples. uint32_t major, minor; FFmpegRuntimeLinker::GetVersion(major, minor); // LibAV 0.8 produces rubbish float interlaved samples, request 16 bits audio. mCodecContext->request_sample_fmt = major == 53 && minor <= 34 ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLT; // FFmpeg will call back to this to negotiate a video pixel format. mCodecContext->get_format = ChoosePixelFormat; mCodecContext->thread_count = PR_GetNumberOfProcessors(); mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME; mCodecContext->thread_safe_callbacks = false; if (mExtraData) { mCodecContext->extradata_size = mExtraData->Length(); // FFmpeg may use SIMD instructions to access the data which reads the // data in 32 bytes block. Must ensure we have enough data to read. mExtraData->AppendElements(FF_INPUT_BUFFER_PADDING_SIZE); mCodecContext->extradata = mExtraData->Elements(); } else { mCodecContext->extradata_size = 0; } if (codec->capabilities & CODEC_CAP_DR1) { mCodecContext->flags |= CODEC_FLAG_EMU_EDGE; } if (avcodec_open2(mCodecContext, codec, nullptr) < 0) { NS_WARNING("Couldn't initialise ffmpeg decoder"); avcodec_close(mCodecContext); av_freep(&mCodecContext); return NS_ERROR_FAILURE; } if (mCodecContext->codec_type == AVMEDIA_TYPE_AUDIO && mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLTP && mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16 && mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16P) { NS_WARNING("FFmpeg audio decoder outputs unsupported audio format."); return NS_ERROR_FAILURE; } mCodecParser = av_parser_init(mCodecID); if (mCodecParser) { mCodecParser->flags |= PARSER_FLAG_COMPLETE_FRAMES; } FFMPEG_LOG("FFmpeg init successful."); return NS_OK; }
nsresult VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth, int32_t aDisplayHeight,TrackRate aTrackRate) { if (aWidth < 1 || aHeight < 1 || aDisplayWidth < 1 || aDisplayHeight < 1 || aTrackRate <= 0) { return NS_ERROR_FAILURE; } ReentrantMonitorAutoEnter mon(mReentrantMonitor); mTrackRate = aTrackRate; mEncodedFrameRate = DEFAULT_ENCODE_FRAMERATE; mEncodedFrameDuration = mTrackRate / mEncodedFrameRate; mFrameWidth = aWidth; mFrameHeight = aHeight; mDisplayWidth = aDisplayWidth; mDisplayHeight = aDisplayHeight; // Encoder configuration structure. vpx_codec_enc_cfg_t config; memset(&config, 0, sizeof(vpx_codec_enc_cfg_t)); if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config, 0)) { return NS_ERROR_FAILURE; } // Creating a wrapper to the image - setting image data to NULL. Actual // pointer will be set in encode. Setting align to 1, as it is meaningless // (actual memory is not allocated). vpx_img_wrap(mVPXImageWrapper, IMG_FMT_I420, mFrameWidth, mFrameHeight, 1, nullptr); config.g_w = mFrameWidth; config.g_h = mFrameHeight; // TODO: Maybe we should have various aFrameRate bitrate pair for each devices? // or for different platform config.rc_target_bitrate = DEFAULT_BITRATE; // in kbit/s // Setting the time base of the codec config.g_timebase.num = 1; config.g_timebase.den = mTrackRate; config.g_error_resilient = 0; config.g_lag_in_frames = 0; // 0- no frame lagging int32_t number_of_cores = PR_GetNumberOfProcessors(); if (mFrameWidth * mFrameHeight > 1280 * 960 && number_of_cores >= 6) { config.g_threads = 3; // 3 threads for 1080p. } else if (mFrameWidth * mFrameHeight > 640 * 480 && number_of_cores >= 3) { config.g_threads = 2; // 2 threads for qHD/HD. } else { config.g_threads = 1; // 1 thread for VGA or less } // rate control settings config.rc_dropframe_thresh = 0; config.rc_end_usage = VPX_CBR; config.g_pass = VPX_RC_ONE_PASS; config.rc_resize_allowed = 1; config.rc_undershoot_pct = 100; config.rc_overshoot_pct = 15; config.rc_buf_initial_sz = 500; config.rc_buf_optimal_sz = 600; config.rc_buf_sz = 1000; config.kf_mode = VPX_KF_AUTO; // Ensure that we can output one I-frame per second. config.kf_max_dist = mEncodedFrameRate; vpx_codec_flags_t flags = 0; flags |= VPX_CODEC_USE_OUTPUT_PARTITION; if (vpx_codec_enc_init(mVPXContext, vpx_codec_vp8_cx(), &config, flags)) { return NS_ERROR_FAILURE; } vpx_codec_control(mVPXContext, VP8E_SET_STATIC_THRESHOLD, 1); vpx_codec_control(mVPXContext, VP8E_SET_CPUUSED, -6); vpx_codec_control(mVPXContext, VP8E_SET_TOKEN_PARTITIONS, VP8_ONE_TOKENPARTITION); mInitialized = true; mon.NotifyAll(); return NS_OK; }
nsresult FFmpegDataDecoder<LIBAV_VER>::InitDecoder() { StaticMutexAutoLock mon(sMonitor); FFMPEG_LOG("Initialising FFmpeg decoder."); if (!sFFmpegInitDone) { av_register_all(); #ifdef DEBUG av_log_set_level(AV_LOG_DEBUG); #endif sFFmpegInitDone = true; } AVCodec* codec = avcodec_find_decoder(mCodecID); if (!codec) { NS_WARNING("Couldn't find ffmpeg decoder"); return NS_ERROR_FAILURE; } if (!(mCodecContext = avcodec_alloc_context3(codec))) { NS_WARNING("Couldn't init ffmpeg context"); return NS_ERROR_FAILURE; } mCodecContext->opaque = this; // FFmpeg takes this as a suggestion for what format to use for audio samples. mCodecContext->request_sample_fmt = AV_SAMPLE_FMT_FLT; // FFmpeg will call back to this to negotiate a video pixel format. mCodecContext->get_format = ChoosePixelFormat; mCodecContext->thread_count = PR_GetNumberOfProcessors(); mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME; mCodecContext->thread_safe_callbacks = false; if (mExtraData) { mCodecContext->extradata_size = mExtraData->Length(); // FFmpeg may use SIMD instructions to access the data which reads the // data in 32 bytes block. Must ensure we have enough data to read. mExtraData->AppendElements(FF_INPUT_BUFFER_PADDING_SIZE); mCodecContext->extradata = mExtraData->Elements(); } else { mCodecContext->extradata_size = 0; } if (codec->capabilities & CODEC_CAP_DR1) { mCodecContext->flags |= CODEC_FLAG_EMU_EDGE; } if (avcodec_open2(mCodecContext, codec, nullptr) < 0) { NS_WARNING("Couldn't initialise ffmpeg decoder"); return NS_ERROR_FAILURE; } if (mCodecContext->codec_type == AVMEDIA_TYPE_AUDIO && mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLTP && mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16 && mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16P) { NS_WARNING("FFmpeg audio decoder outputs unsupported audio format."); return NS_ERROR_FAILURE; } FFMPEG_LOG("FFmpeg init successful."); return NS_OK; }