Loading media/libmediatranscoding/transcoder/MediaTranscoder.cpp +19 −33 Original line number Diff line number Diff line Loading @@ -23,24 +23,13 @@ #include <media/MediaSampleReaderNDK.h> #include <media/MediaSampleWriter.h> #include <media/MediaTranscoder.h> #include <media/NdkCommon.h> #include <media/PassthroughTrackTranscoder.h> #include <media/VideoTrackTranscoder.h> #include <unistd.h> namespace android { #define DEFINE_FORMAT_VALUE_COPY_FUNC(_type, _typeName) \ static void copy##_typeName(const char* key, AMediaFormat* to, AMediaFormat* from) { \ _type value; \ if (AMediaFormat_get##_typeName(from, key, &value)) { \ AMediaFormat_set##_typeName(to, key, value); \ } \ } DEFINE_FORMAT_VALUE_COPY_FUNC(const char*, String); DEFINE_FORMAT_VALUE_COPY_FUNC(int64_t, Int64); DEFINE_FORMAT_VALUE_COPY_FUNC(int32_t, Int32); static AMediaFormat* mergeMediaFormats(AMediaFormat* base, AMediaFormat* overlay) { if (base == nullptr || overlay == nullptr) { LOG(ERROR) << "Cannot merge null formats"; Loading @@ -58,29 +47,26 @@ static AMediaFormat* mergeMediaFormats(AMediaFormat* base, AMediaFormat* overlay // along with their value types and copy the ones that are present. A better solution would be // to either implement required functions in NDK or to parse the overlay format's string // representation and copy all existing keys. static const struct { const char* key; void (*copyValue)(const char* key, AMediaFormat* to, AMediaFormat* from); } kSupportedConfigs[] = { {AMEDIAFORMAT_KEY_MIME, copyString}, {AMEDIAFORMAT_KEY_DURATION, copyInt64}, {AMEDIAFORMAT_KEY_WIDTH, copyInt32}, {AMEDIAFORMAT_KEY_HEIGHT, copyInt32}, {AMEDIAFORMAT_KEY_BIT_RATE, copyInt32}, {AMEDIAFORMAT_KEY_PROFILE, copyInt32}, {AMEDIAFORMAT_KEY_LEVEL, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_FORMAT, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_RANGE, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_STANDARD, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_TRANSFER, copyInt32}, {AMEDIAFORMAT_KEY_FRAME_RATE, copyInt32}, {AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, copyInt32}, static const AMediaFormatUtils::EntryCopier kSupportedFormatEntries[] = { ENTRY_COPIER(AMEDIAFORMAT_KEY_MIME, String), ENTRY_COPIER(AMEDIAFORMAT_KEY_DURATION, Int64), ENTRY_COPIER(AMEDIAFORMAT_KEY_WIDTH, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_HEIGHT, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_BIT_RATE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_PROFILE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_LEVEL, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_FORMAT, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_FRAME_RATE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32), ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32), }; const size_t entryCount = sizeof(kSupportedFormatEntries) / sizeof(kSupportedFormatEntries[0]); for (int i = 0; i < (sizeof(kSupportedConfigs) / sizeof(kSupportedConfigs[0])); ++i) { kSupportedConfigs[i].copyValue(kSupportedConfigs[i].key, format, overlay); } AMediaFormatUtils::CopyFormatEntries(overlay, format, kSupportedFormatEntries, entryCount); return format; } Loading media/libmediatranscoding/transcoder/NdkCommon.cpp +36 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NdkCommon" #include <log/log.h> #include <android-base/logging.h> #include <media/NdkCommon.h> #include <cstdio> Loading @@ -39,3 +39,38 @@ const char* TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP = "allow-frame-drop"; const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync"; const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate"; const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES = "max-bframes"; namespace AMediaFormatUtils { #define DEFINE_FORMAT_VALUE_COPY_FUNC(_type, _typeName) \ bool CopyFormatEntry##_typeName(const char* key, AMediaFormat* from, AMediaFormat* to) { \ _type value; \ if (AMediaFormat_get##_typeName(from, key, &value)) { \ AMediaFormat_set##_typeName(to, key, value); \ return true; \ } \ return false; \ } DEFINE_FORMAT_VALUE_COPY_FUNC(const char*, String); DEFINE_FORMAT_VALUE_COPY_FUNC(int64_t, Int64); DEFINE_FORMAT_VALUE_COPY_FUNC(int32_t, Int32); DEFINE_FORMAT_VALUE_COPY_FUNC(float, Float); void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to, const EntryCopier* entries, size_t entryCount) { if (from == nullptr || to == nullptr) { LOG(ERROR) << "Cannot copy null formats"; return; } else if (entries == nullptr || entryCount < 1) { LOG(WARNING) << "No entries to copy"; return; } for (size_t i = 0; i < entryCount; ++i) { if (!entries[i].copy(entries[i].key, from, to) && entries[i].copy2 != nullptr) { entries[i].copy2(entries[i].key, from, to); } } } } // namespace AMediaFormatUtils No newline at end of file media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -270,6 +270,15 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( // Prevent decoder from overwriting frames that the encoder has not yet consumed. AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0); // Copy over configurations that apply to both encoder and decoder. static const AMediaFormatUtils::EntryCopier kEncoderEntriesToCopy[] = { ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32), }; const size_t entryCount = sizeof(kEncoderEntriesToCopy) / sizeof(kEncoderEntriesToCopy[0]); AMediaFormatUtils::CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy, entryCount); status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */, 0 /* flags */); if (status != AMEDIA_OK) { Loading media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp +75 −14 Original line number Diff line number Diff line Loading @@ -76,11 +76,27 @@ private: bool mFinished = false; }; static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName, const std::string& dstFileName, bool includeAudio, bool transcodeVideo = true) { static AMediaFormat* CreateDefaultVideoFormat() { // Default bitrate static constexpr int32_t kVideoBitRate = 20 * 1000 * 1000; // 20Mbs AMediaFormat* videoFormat = AMediaFormat_new(); AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_BIT_RATE, kVideoBitRate); return videoFormat; } /** * Callback to configure tracks for transcoding. * @param mime The source track mime type. * @param dstFormat The destination format if the track should be transcoded or nullptr if the track * should be passed through. * @return True if the track should be included in the output file. */ using TrackSelectionCallback = std::function<bool(const char* mime, AMediaFormat** dstFormat)>; static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName, const std::string& dstFileName, TrackSelectionCallback trackSelectionCallback) { // Write-only, create file if non-existent. static constexpr int kDstOpenFlags = O_WRONLY | O_CREAT; // User R+W permission. Loading Loading @@ -133,21 +149,17 @@ static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFi } if (strncmp(mime, "video/", 6) == 0) { if (transcodeVideo) { dstFormat = AMediaFormat_new(); AMediaFormat_setInt32(dstFormat, AMEDIAFORMAT_KEY_BIT_RATE, kVideoBitRate); } int32_t frameCount; if (AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT, &frameCount)) { state.counters["VideoFrameRate"] = benchmark::Counter(frameCount, benchmark::Counter::kIsRate); } } else if (!includeAudio && strncmp(mime, "audio/", 6) == 0) { continue; } if (trackSelectionCallback(mime, &dstFormat)) { status = transcoder->configureTrackFormat(i, dstFormat); } if (dstFormat != nullptr) { AMediaFormat_delete(dstFormat); } Loading Loading @@ -179,6 +191,21 @@ exit: if (dstFd > 0) close(dstFd); } static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName, const std::string& dstFileName, bool includeAudio, bool transcodeVideo) { TranscodeMediaFile(state, srcFileName, dstFileName, [=](const char* mime, AMediaFormat** dstFormatOut) -> bool { *dstFormatOut = nullptr; if (strncmp(mime, "video/", 6) == 0 && transcodeVideo) { *dstFormatOut = CreateDefaultVideoFormat(); } else if (strncmp(mime, "audio/", 6) == 0 && !includeAudio) { return false; } return true; }); } // Benchmark registration wrapper for transcoding. #define TRANSCODER_BENCHMARK(func) \ BENCHMARK(func)->UseRealTime()->MeasureProcessCPUTime()->Unit(benchmark::kMillisecond) Loading @@ -186,19 +213,51 @@ exit: static void BM_TranscodeAvc2AvcAudioVideo2AudioVideo(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4", true /* includeAudio */); true /* includeAudio */, true /* transcodeVideo */); } static void BM_TranscodeAvc2AvcAudioVideo2Video(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_V.mp4", false /* includeAudio */); false /* includeAudio */, true /* transcodeVideo */); } static void BM_TranscodeAvc2AvcVideo2Video(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4", false /* includeAudio */); false /* includeAudio */, true /* transcodeVideo */); } static void BM_TranscodeAvc2AvcAV2AVMaxOperatingRate(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4", [](const char* mime, AMediaFormat** dstFormatOut) -> bool { AMediaFormat* dstFormat = nullptr; if (strncmp(mime, "video/", 6) == 0) { dstFormat = CreateDefaultVideoFormat(); AMediaFormat_setFloat(dstFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, INT32_MAX); AMediaFormat_setInt32(dstFormat, AMEDIAFORMAT_KEY_PRIORITY, 1); } *dstFormatOut = dstFormat; return true; }); } static void BM_TranscodeAvc2AvcV2VMaxOperatingRate(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4", [](const char* mime, AMediaFormat** dstFormatOut) -> bool { if (strncmp(mime, "video/", 6) == 0) { AMediaFormat* dstFormat = CreateDefaultVideoFormat(); AMediaFormat_setFloat(dstFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, INT32_MAX); AMediaFormat_setInt32(dstFormat, AMEDIAFORMAT_KEY_PRIORITY, 1); *dstFormatOut = dstFormat; return true; } return false; }); } static void BM_TranscodeAudioVideoPassthrough(benchmark::State& state) { Loading @@ -215,6 +274,8 @@ static void BM_TranscodeVideoPassthrough(benchmark::State& state) { TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2AudioVideo); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2Video); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcVideo2Video); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AVMaxOperatingRate); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcV2VMaxOperatingRate); TRANSCODER_BENCHMARK(BM_TranscodeAudioVideoPassthrough); TRANSCODER_BENCHMARK(BM_TranscodeVideoPassthrough); Loading media/libmediatranscoding/transcoder/include/media/NdkCommon.h +25 −0 Original line number Diff line number Diff line Loading @@ -54,4 +54,29 @@ static constexpr int TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1; static constexpr int kBitrateModeConstant = 2; namespace AMediaFormatUtils { typedef struct { const char* key; bool (*copy)(const char* key, AMediaFormat* from, AMediaFormat* to); bool (*copy2)(const char* key, AMediaFormat* from, AMediaFormat* to); } EntryCopier; #define ENTRY_COPIER(keyName, typeName) \ { keyName, AMediaFormatUtils::CopyFormatEntry##typeName, nullptr } #define ENTRY_COPIER2(keyName, typeName, typeName2) \ { \ keyName, AMediaFormatUtils::CopyFormatEntry##typeName, \ AMediaFormatUtils::CopyFormatEntry##typeName2 \ } bool CopyFormatEntryString(const char* key, AMediaFormat* from, AMediaFormat* to); bool CopyFormatEntryInt64(const char* key, AMediaFormat* from, AMediaFormat* to); bool CopyFormatEntryInt32(const char* key, AMediaFormat* from, AMediaFormat* to); bool CopyFormatEntryFloat(const char* key, AMediaFormat* from, AMediaFormat* to); void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to, const EntryCopier* entries, size_t entryCount); } // namespace AMediaFormatUtils #endif // ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H Loading
media/libmediatranscoding/transcoder/MediaTranscoder.cpp +19 −33 Original line number Diff line number Diff line Loading @@ -23,24 +23,13 @@ #include <media/MediaSampleReaderNDK.h> #include <media/MediaSampleWriter.h> #include <media/MediaTranscoder.h> #include <media/NdkCommon.h> #include <media/PassthroughTrackTranscoder.h> #include <media/VideoTrackTranscoder.h> #include <unistd.h> namespace android { #define DEFINE_FORMAT_VALUE_COPY_FUNC(_type, _typeName) \ static void copy##_typeName(const char* key, AMediaFormat* to, AMediaFormat* from) { \ _type value; \ if (AMediaFormat_get##_typeName(from, key, &value)) { \ AMediaFormat_set##_typeName(to, key, value); \ } \ } DEFINE_FORMAT_VALUE_COPY_FUNC(const char*, String); DEFINE_FORMAT_VALUE_COPY_FUNC(int64_t, Int64); DEFINE_FORMAT_VALUE_COPY_FUNC(int32_t, Int32); static AMediaFormat* mergeMediaFormats(AMediaFormat* base, AMediaFormat* overlay) { if (base == nullptr || overlay == nullptr) { LOG(ERROR) << "Cannot merge null formats"; Loading @@ -58,29 +47,26 @@ static AMediaFormat* mergeMediaFormats(AMediaFormat* base, AMediaFormat* overlay // along with their value types and copy the ones that are present. A better solution would be // to either implement required functions in NDK or to parse the overlay format's string // representation and copy all existing keys. static const struct { const char* key; void (*copyValue)(const char* key, AMediaFormat* to, AMediaFormat* from); } kSupportedConfigs[] = { {AMEDIAFORMAT_KEY_MIME, copyString}, {AMEDIAFORMAT_KEY_DURATION, copyInt64}, {AMEDIAFORMAT_KEY_WIDTH, copyInt32}, {AMEDIAFORMAT_KEY_HEIGHT, copyInt32}, {AMEDIAFORMAT_KEY_BIT_RATE, copyInt32}, {AMEDIAFORMAT_KEY_PROFILE, copyInt32}, {AMEDIAFORMAT_KEY_LEVEL, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_FORMAT, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_RANGE, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_STANDARD, copyInt32}, {AMEDIAFORMAT_KEY_COLOR_TRANSFER, copyInt32}, {AMEDIAFORMAT_KEY_FRAME_RATE, copyInt32}, {AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, copyInt32}, static const AMediaFormatUtils::EntryCopier kSupportedFormatEntries[] = { ENTRY_COPIER(AMEDIAFORMAT_KEY_MIME, String), ENTRY_COPIER(AMEDIAFORMAT_KEY_DURATION, Int64), ENTRY_COPIER(AMEDIAFORMAT_KEY_WIDTH, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_HEIGHT, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_BIT_RATE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_PROFILE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_LEVEL, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_FORMAT, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_FRAME_RATE, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32), ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32), }; const size_t entryCount = sizeof(kSupportedFormatEntries) / sizeof(kSupportedFormatEntries[0]); for (int i = 0; i < (sizeof(kSupportedConfigs) / sizeof(kSupportedConfigs[0])); ++i) { kSupportedConfigs[i].copyValue(kSupportedConfigs[i].key, format, overlay); } AMediaFormatUtils::CopyFormatEntries(overlay, format, kSupportedFormatEntries, entryCount); return format; } Loading
media/libmediatranscoding/transcoder/NdkCommon.cpp +36 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NdkCommon" #include <log/log.h> #include <android-base/logging.h> #include <media/NdkCommon.h> #include <cstdio> Loading @@ -39,3 +39,38 @@ const char* TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP = "allow-frame-drop"; const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync"; const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate"; const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES = "max-bframes"; namespace AMediaFormatUtils { #define DEFINE_FORMAT_VALUE_COPY_FUNC(_type, _typeName) \ bool CopyFormatEntry##_typeName(const char* key, AMediaFormat* from, AMediaFormat* to) { \ _type value; \ if (AMediaFormat_get##_typeName(from, key, &value)) { \ AMediaFormat_set##_typeName(to, key, value); \ return true; \ } \ return false; \ } DEFINE_FORMAT_VALUE_COPY_FUNC(const char*, String); DEFINE_FORMAT_VALUE_COPY_FUNC(int64_t, Int64); DEFINE_FORMAT_VALUE_COPY_FUNC(int32_t, Int32); DEFINE_FORMAT_VALUE_COPY_FUNC(float, Float); void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to, const EntryCopier* entries, size_t entryCount) { if (from == nullptr || to == nullptr) { LOG(ERROR) << "Cannot copy null formats"; return; } else if (entries == nullptr || entryCount < 1) { LOG(WARNING) << "No entries to copy"; return; } for (size_t i = 0; i < entryCount; ++i) { if (!entries[i].copy(entries[i].key, from, to) && entries[i].copy2 != nullptr) { entries[i].copy2(entries[i].key, from, to); } } } } // namespace AMediaFormatUtils No newline at end of file
media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -270,6 +270,15 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( // Prevent decoder from overwriting frames that the encoder has not yet consumed. AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0); // Copy over configurations that apply to both encoder and decoder. static const AMediaFormatUtils::EntryCopier kEncoderEntriesToCopy[] = { ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32), ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32), }; const size_t entryCount = sizeof(kEncoderEntriesToCopy) / sizeof(kEncoderEntriesToCopy[0]); AMediaFormatUtils::CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy, entryCount); status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */, 0 /* flags */); if (status != AMEDIA_OK) { Loading
media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp +75 −14 Original line number Diff line number Diff line Loading @@ -76,11 +76,27 @@ private: bool mFinished = false; }; static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName, const std::string& dstFileName, bool includeAudio, bool transcodeVideo = true) { static AMediaFormat* CreateDefaultVideoFormat() { // Default bitrate static constexpr int32_t kVideoBitRate = 20 * 1000 * 1000; // 20Mbs AMediaFormat* videoFormat = AMediaFormat_new(); AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_BIT_RATE, kVideoBitRate); return videoFormat; } /** * Callback to configure tracks for transcoding. * @param mime The source track mime type. * @param dstFormat The destination format if the track should be transcoded or nullptr if the track * should be passed through. * @return True if the track should be included in the output file. */ using TrackSelectionCallback = std::function<bool(const char* mime, AMediaFormat** dstFormat)>; static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName, const std::string& dstFileName, TrackSelectionCallback trackSelectionCallback) { // Write-only, create file if non-existent. static constexpr int kDstOpenFlags = O_WRONLY | O_CREAT; // User R+W permission. Loading Loading @@ -133,21 +149,17 @@ static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFi } if (strncmp(mime, "video/", 6) == 0) { if (transcodeVideo) { dstFormat = AMediaFormat_new(); AMediaFormat_setInt32(dstFormat, AMEDIAFORMAT_KEY_BIT_RATE, kVideoBitRate); } int32_t frameCount; if (AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT, &frameCount)) { state.counters["VideoFrameRate"] = benchmark::Counter(frameCount, benchmark::Counter::kIsRate); } } else if (!includeAudio && strncmp(mime, "audio/", 6) == 0) { continue; } if (trackSelectionCallback(mime, &dstFormat)) { status = transcoder->configureTrackFormat(i, dstFormat); } if (dstFormat != nullptr) { AMediaFormat_delete(dstFormat); } Loading Loading @@ -179,6 +191,21 @@ exit: if (dstFd > 0) close(dstFd); } static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName, const std::string& dstFileName, bool includeAudio, bool transcodeVideo) { TranscodeMediaFile(state, srcFileName, dstFileName, [=](const char* mime, AMediaFormat** dstFormatOut) -> bool { *dstFormatOut = nullptr; if (strncmp(mime, "video/", 6) == 0 && transcodeVideo) { *dstFormatOut = CreateDefaultVideoFormat(); } else if (strncmp(mime, "audio/", 6) == 0 && !includeAudio) { return false; } return true; }); } // Benchmark registration wrapper for transcoding. #define TRANSCODER_BENCHMARK(func) \ BENCHMARK(func)->UseRealTime()->MeasureProcessCPUTime()->Unit(benchmark::kMillisecond) Loading @@ -186,19 +213,51 @@ exit: static void BM_TranscodeAvc2AvcAudioVideo2AudioVideo(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4", true /* includeAudio */); true /* includeAudio */, true /* transcodeVideo */); } static void BM_TranscodeAvc2AvcAudioVideo2Video(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_V.mp4", false /* includeAudio */); false /* includeAudio */, true /* transcodeVideo */); } static void BM_TranscodeAvc2AvcVideo2Video(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4", false /* includeAudio */); false /* includeAudio */, true /* transcodeVideo */); } static void BM_TranscodeAvc2AvcAV2AVMaxOperatingRate(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4", [](const char* mime, AMediaFormat** dstFormatOut) -> bool { AMediaFormat* dstFormat = nullptr; if (strncmp(mime, "video/", 6) == 0) { dstFormat = CreateDefaultVideoFormat(); AMediaFormat_setFloat(dstFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, INT32_MAX); AMediaFormat_setInt32(dstFormat, AMEDIAFORMAT_KEY_PRIORITY, 1); } *dstFormatOut = dstFormat; return true; }); } static void BM_TranscodeAvc2AvcV2VMaxOperatingRate(benchmark::State& state) { TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4", "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4", [](const char* mime, AMediaFormat** dstFormatOut) -> bool { if (strncmp(mime, "video/", 6) == 0) { AMediaFormat* dstFormat = CreateDefaultVideoFormat(); AMediaFormat_setFloat(dstFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, INT32_MAX); AMediaFormat_setInt32(dstFormat, AMEDIAFORMAT_KEY_PRIORITY, 1); *dstFormatOut = dstFormat; return true; } return false; }); } static void BM_TranscodeAudioVideoPassthrough(benchmark::State& state) { Loading @@ -215,6 +274,8 @@ static void BM_TranscodeVideoPassthrough(benchmark::State& state) { TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2AudioVideo); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2Video); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcVideo2Video); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AVMaxOperatingRate); TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcV2VMaxOperatingRate); TRANSCODER_BENCHMARK(BM_TranscodeAudioVideoPassthrough); TRANSCODER_BENCHMARK(BM_TranscodeVideoPassthrough); Loading
media/libmediatranscoding/transcoder/include/media/NdkCommon.h +25 −0 Original line number Diff line number Diff line Loading @@ -54,4 +54,29 @@ static constexpr int TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1; static constexpr int kBitrateModeConstant = 2; namespace AMediaFormatUtils { typedef struct { const char* key; bool (*copy)(const char* key, AMediaFormat* from, AMediaFormat* to); bool (*copy2)(const char* key, AMediaFormat* from, AMediaFormat* to); } EntryCopier; #define ENTRY_COPIER(keyName, typeName) \ { keyName, AMediaFormatUtils::CopyFormatEntry##typeName, nullptr } #define ENTRY_COPIER2(keyName, typeName, typeName2) \ { \ keyName, AMediaFormatUtils::CopyFormatEntry##typeName, \ AMediaFormatUtils::CopyFormatEntry##typeName2 \ } bool CopyFormatEntryString(const char* key, AMediaFormat* from, AMediaFormat* to); bool CopyFormatEntryInt64(const char* key, AMediaFormat* from, AMediaFormat* to); bool CopyFormatEntryInt32(const char* key, AMediaFormat* from, AMediaFormat* to); bool CopyFormatEntryFloat(const char* key, AMediaFormat* from, AMediaFormat* to); void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to, const EntryCopier* entries, size_t entryCount); } // namespace AMediaFormatUtils #endif // ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H