/* * Copyright (c) 2021-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define HST_LOG_TAG "FfmpegTrackMeta" #include "ffmpeg_track_meta.h" #include "foundation/log.h" #include "foundation/utils/constants.h" #include "plugins/ffmpeg_adapter/utils/aac_audio_config_parser.h" #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h" #ifdef VIDEO_SUPPORT #include "plugins/ffmpeg_adapter/utils/avc_config_data_parser.h" #endif namespace OHOS { namespace Media { namespace Plugin { namespace Ffmpeg { namespace { using ConvertFunc = void (*)(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta); struct StreamConvertor { AVCodecID codecId; ConvertFunc convertor; }; StreamConvertor g_streamConvertors[] = {{AV_CODEC_ID_PCM_S16LE, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_PCM_S16BE, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_PCM_U16LE, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_PCM_U16BE, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_PCM_S24LE, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_PCM_F32LE, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_PCM_S8, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_PCM_U8, ConvertRawAudioStreamToMetaInfo}, {AV_CODEC_ID_MP1, ConvertMP1StreamToMetaInfo}, {AV_CODEC_ID_MP2, ConvertMP2StreamToMetaInfo}, {AV_CODEC_ID_MP3, ConvertMP3StreamToMetaInfo}, {AV_CODEC_ID_AAC, ConvertAACStreamToMetaInfo}, {AV_CODEC_ID_AAC_LATM, ConvertAACLatmStreamToMetaInfo}, {AV_CODEC_ID_VORBIS, ConvertVorbisStreamToMetaInfo}, {AV_CODEC_ID_FLAC, ConvertFLACStreamToMetaInfo}, {AV_CODEC_ID_APE, ConvertAPEStreamToMetaInfo}, #ifdef AVS3DA_SUPPORT {AV_CODEC_ID_AVS3DA, ConvertAVS3DAStreamToMetaInfo}, #endif #ifdef VIDEO_SUPPORT {AV_CODEC_ID_H264, ConvertAVCStreamToMetaInfo}, #endif {AV_CODEC_ID_AMR_NB, ConvertAMRnbStreamToMetaInfo}, {AV_CODEC_ID_AMR_WB, ConvertAMRwbStreamToMetaInfo}, {AV_CODEC_ID_OPUS, ConvertOPUSStreamToMetaInfo}, }; bool IsPcmStream(const AVStream& avStream) { auto codecId = avStream.codecpar->codec_id; return codecId == AV_CODEC_ID_PCM_S16LE || codecId == AV_CODEC_ID_PCM_S16BE || codecId == AV_CODEC_ID_PCM_U16LE || codecId == AV_CODEC_ID_PCM_U16BE || codecId == AV_CODEC_ID_PCM_S8 || codecId == AV_CODEC_ID_PCM_U8 || codecId == AV_CODEC_ID_PCM_F32LE; } void ConvertCommonTrackToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(avStream.index); meta.Set( ConvertTimeFromFFmpeg(avStream.duration, avStream.time_base)); meta.Set( ConvertTimeFromFFmpeg(avStream.start_time, avStream.time_base)); if (avCodecContext->extradata_size > 0) { CodecConfig codecConfig; codecConfig.assign(avCodecContext->extradata, avCodecContext->extradata + avCodecContext->extradata_size); meta.Set(std::move(codecConfig)); } int64_t bitRate = avCodecContext->bit_rate; if (!bitRate) { bitRate = avFormatContext->bit_rate; } FALSE_LOG(meta.Set(bitRate)); FALSE_LOG(meta.Set(avCodecContext->bits_per_coded_sample)); } #ifdef VIDEO_SUPPORT void ConvertCommonVideoTrackToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { ConvertCommonTrackToMetaInfo(avStream, avFormatContext, avCodecContext, meta); meta.Set(avCodecContext->width); meta.Set(avCodecContext->height); uint32_t frameRate = 0; if (avStream.avg_frame_rate.den) { static constexpr int32_t factor = 100; frameRate = static_cast( static_cast(avStream.avg_frame_rate.num) / avStream.avg_frame_rate.den * factor); } meta.Set(frameRate); } #endif void ConvertCommonAudioStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { ConvertCommonTrackToMetaInfo(avStream, avFormatContext, avCodecContext, meta); if (avCodecContext->channels != -1) { meta.Set(avCodecContext->sample_rate); meta.Set(avCodecContext->channels); meta.Set(ConvertChannelLayoutFromFFmpeg(avCodecContext->channels, avCodecContext->channel_layout)); // ffmpeg defaults to 1024 samples per frame for planar PCM in each buffer (one for each channel). uint32_t samplesPerFrame = 1024; if (!IsPcmStream(avStream) && avCodecContext->frame_size != 0) { samplesPerFrame = static_cast(avCodecContext->frame_size); } meta.Set(samplesPerFrame); if (avCodecContext->sample_fmt != AV_SAMPLE_FMT_NONE) { meta.Set(ConvFf2PSampleFmt(avCodecContext->sample_fmt)); } else { meta.Set(AudioSampleFormat::S16); } } } } // namespace void ConvertRawAudioStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_RAW); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } void ConvertMP1StreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_MPEG); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); meta.Set(1); meta.Set(1); } void ConvertMP2StreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_MPEG); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); meta.Set(1); meta.Set(2); // 2 } void ConvertMP3StreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_MPEG); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); meta.Set(1); meta.Set(3); // 3 } void ConvertFLACStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_FLAC); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } void ConvertAPEStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_APE); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } void ConvertAMRnbStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_AMR_NB); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } void ConvertAMRwbStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_AMR_WB); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } void ConvertOPUSStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_OPUS); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } void ConvertVorbisStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_VORBIS); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } void ConvertAACStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_AAC); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); meta.Set(4); // 4 meta.Set(AudioAacProfile::LC); if (avCodecContext->extradata_size > 0) { std::vector codecConfig; codecConfig.assign(avCodecContext->extradata, avCodecContext->extradata + avCodecContext->extradata_size); meta.Set(std::move(codecConfig)); AACAudioConfigParser parser(avCodecContext->extradata, avCodecContext->extradata_size); if (!parser.ParseConfigs()) { return; } meta.Set(parser.GetLevel()); auto profile = parser.GetProfile(); if (profile != AudioAacProfile::NONE) { meta.Set(profile); } } else { meta.Set(AudioAacStreamFormat::MP4ADTS); } } void ConvertAACLatmStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_AAC_LATM); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); meta.Set(4); // 4 meta.Set(AudioAacStreamFormat::MP4LOAS); meta.Set(avCodecContext->bits_per_coded_sample); } #ifdef AVS3DA_SUPPORT void ConvertAVS3DAStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_AUDIO_AVS3DA); ConvertCommonAudioStreamToMetaInfo(avStream, avFormatContext, avCodecContext, meta); } #endif #ifdef VIDEO_SUPPORT void ConvertAVCStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Set(MEDIA_MIME_VIDEO_H264); ConvertCommonVideoTrackToMetaInfo(avStream, avFormatContext, avCodecContext, meta); if (avCodecContext->extradata_size > 0) { AVCConfigDataParser parser(avCodecContext->extradata, avCodecContext->extradata_size); if (!parser.ParseConfigData()) { return; } std::shared_ptr cfgData = nullptr; size_t cfgDataSize = 0; if (parser.GetNewConfigData(cfgData, cfgDataSize) && (cfgData != nullptr) && (cfgDataSize != 0)) { std::vector codecConfig; codecConfig.assign(cfgData.get(), cfgData.get() + cfgDataSize); meta.Set(std::move(codecConfig)); } } } #endif void ConvertAVStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& avFormatContext, const std::shared_ptr& avCodecContext, Meta& meta) { meta.Clear(); auto codecId = avStream.codecpar->codec_id; for (auto& streamConvertor : g_streamConvertors) { if (streamConvertor.codecId == codecId) { streamConvertor.convertor(avStream, avFormatContext, avCodecContext, meta); return; } } MEDIA_LOG_E("unsupported codec id: " PUBLIC_LOG_D32 ", name: " PUBLIC_LOG_S, codecId, avcodec_get_name(codecId)); } } // namespace Ffmpeg } // namespace Plugin } // namespace Media } // namespace OHOS