/* * Copyright (C) 2022 The Android Open Source Project * * 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. */ #include #include #include #include #include #include const std::string kMuxerFile = "mediaMuxer"; const std::string kAppendFile = "mediaAppend"; constexpr size_t kMinBytes = 0; constexpr size_t kMaxBytes = 1000; constexpr size_t kMinChoice = 0; constexpr size_t kMaxChoice = 7; constexpr size_t kMaxStringLength = 20; constexpr size_t kOffset = 0; constexpr OutputFormat kOutputFormat[] = {AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4, AMEDIAMUXER_OUTPUT_FORMAT_WEBM, AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP}; constexpr AppendMode kAppendMode[] = {AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP, AMEDIAMUXER_APPEND_TO_EXISTING_DATA}; const std::string kAudioMimeType[] = {"audio/3gpp", "audio/amr-wb", "audio/mp4a-latm", "audio/flac", "audio/vorbis", "audio/opus"}; const std::string kVideoMimeType[] = {"video/x-vnd.on2.vp8", "video/x-vnd.on2.vp9", "video/av01", "video/avc", "video/hevc", "video/mp4v-es", "video/3gpp"}; void getSampleAudioFormat(FuzzedDataProvider& fdp, AMediaFormat* format) { std::string mimeType = fdp.ConsumeBool() ? fdp.ConsumeRandomLengthString(kMaxStringLength) : fdp.PickValueInArray(kAudioMimeType); AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mimeType.c_str()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, fdp.ConsumeIntegral()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, fdp.ConsumeIntegral()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, fdp.ConsumeIntegral()); AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, fdp.ConsumeIntegral()); } void getSampleVideoFormat(FuzzedDataProvider& fdp, AMediaFormat* format) { std::string mimeType = fdp.ConsumeBool() ? fdp.ConsumeRandomLengthString(kMaxStringLength) : fdp.PickValueInArray(kAudioMimeType); AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mimeType.c_str()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, fdp.ConsumeIntegral()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, fdp.ConsumeIntegral()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, fdp.ConsumeIntegral()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, fdp.ConsumeIntegral()); AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, fdp.ConsumeFloatingPoint()); AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_CAPTURE_RATE, fdp.ConsumeFloatingPoint()); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, fdp.ConsumeIntegral()); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { /** * Create a threadpool for incoming binder transactions, * without this muxer results in a DoS after few instances. */ ABinderProcess_startThreadPool(); FuzzedDataProvider fdp(data, size); /** * memfd_create() creates an anonymous file and returns a file * descriptor that refers to it. MFD_ALLOW_SEALING allow sealing * operations on this file. */ int32_t fd = -1; AMediaMuxer* muxer = nullptr; if (fdp.ConsumeBool()) { fd = memfd_create(kMuxerFile.c_str(), MFD_ALLOW_SEALING); muxer = AMediaMuxer_new(fd, fdp.ConsumeBool() ? fdp.PickValueInArray(kOutputFormat) : (OutputFormat)fdp.ConsumeIntegral()); } else { fd = memfd_create(kAppendFile.c_str(), MFD_ALLOW_SEALING); std::vector appendData = fdp.ConsumeBytes(fdp.ConsumeIntegralInRange(kMinBytes, kMaxBytes)); write(fd, appendData.data(), appendData.size()); muxer = AMediaMuxer_append(fd, fdp.PickValueInArray(kAppendMode) /* mode */); } if (!muxer) { close(fd); return 0; } AMediaFormat* mediaFormat = nullptr; ssize_t trackIdx = 0; while (fdp.remaining_bytes()) { int32_t kSwitchChoice = fdp.ConsumeIntegralInRange(kMinChoice, kMaxChoice); switch (kSwitchChoice) { case 0: { AMediaMuxer_setLocation(muxer, fdp.ConsumeFloatingPoint() /* latitude */, fdp.ConsumeFloatingPoint() /* longitude */); break; } case 1: { AMediaMuxer_setOrientationHint(muxer, fdp.ConsumeIntegral() /* degrees */); break; } case 2: { AMediaMuxer_start(muxer); break; } case 3: { AMediaMuxer_stop(muxer); break; } case 4: { AMediaMuxer_getTrackCount(muxer); break; } case 5: { AMediaFormat* getFormat = AMediaMuxer_getTrackFormat(muxer, fdp.ConsumeIntegral() /* idx */); AMediaFormat_delete(getFormat); break; } case 6: { mediaFormat = AMediaFormat_new(); fdp.ConsumeBool() ? getSampleAudioFormat(fdp, mediaFormat) : getSampleVideoFormat(fdp, mediaFormat); trackIdx = AMediaMuxer_addTrack(muxer, mediaFormat); AMediaFormat_delete(mediaFormat); break; } default: { std::vector sampleData = fdp.ConsumeBytes( fdp.ConsumeIntegralInRange(kMinBytes, kMaxBytes)); AMediaCodecBufferInfo codecBuffer; codecBuffer.size = sampleData.size(); codecBuffer.offset = kOffset; codecBuffer.presentationTimeUs = fdp.ConsumeIntegral(); codecBuffer.flags = fdp.ConsumeIntegral(); AMediaMuxer_writeSampleData( muxer, fdp.ConsumeBool() ? trackIdx : fdp.ConsumeIntegral() /* trackIdx */, sampleData.data(), &codecBuffer); break; } } } AMediaMuxer_delete(muxer); close(fd); return 0; }