* Copyright (c) 2025 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.
*/
#include <cstddef>
#include <cstdint>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <iostream>
#include <fuzzer/FuzzedDataProvider.h>
#include "securec.h"
#include "demuxer_plugin_manager.h"
#include "stream_demuxer.h"
#define FUZZ_PROJECT_NAME "demuxerpluginmanager_fuzzer"
using namespace std;
using namespace OHOS::Media;
namespace OHOS {
const char *MP4_PATH = "/data/test/fuzz_create.mp4";
const int64_t INVALID_STREAM_OR_TRACK_ID = -1;
const int64_t AUDIO_TRACK = 1;
const int64_t VIDEO_TRACK = 0;
const int64_t SUBTITLE_TRACK = 2;
const int64_t EXPECT_SIZE = 37;
const int64_t SELECT_TRACK = 4;
bool CheckDataValidity(FuzzedDataProvider *fdp, size_t dataSize)
{
if (dataSize < EXPECT_SIZE) {
return false;
}
int32_t fd = open(MP4_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) {
return false;
}
uint8_t *pstream = nullptr;
uint16_t framesize = dataSize - EXPECT_SIZE;
pstream = (uint8_t *)malloc(framesize * sizeof(uint8_t));
if (!pstream) {
std::cerr << "Memory alloction failed" << std::endl;
close(fd);
return false;
}
fdp->ConsumeData(pstream, framesize);
int len = write(fd, pstream, framesize);
if (len <= 0) {
close(fd);
free(pstream);
pstream = nullptr;
return false;
}
close(fd);
free(pstream);
pstream = nullptr;
return true;
}
bool DemuxerPluginManagerFuzzTest(const uint8_t *data, size_t size)
{
FuzzedDataProvider fdp(data, size);
if (!CheckDataValidity(&fdp, size)) {
return false;
}
std::shared_ptr<OHOS::Media::DemuxerPluginManager> demuxerPluginManager_ =
std::make_shared<OHOS::Media::DemuxerPluginManager>();
std::shared_ptr<OHOS::Media::BaseStreamDemuxer> streamDemuxer =
std::make_shared<StreamDemuxer>();
std::shared_ptr<MediaSource> mediaSource =
std::make_shared<MediaSource>(MP4_PATH);
std::shared_ptr<Source> source = std::make_shared<Source>();
auto res = source->SetSource(mediaSource);
if (res != Status::OK) {
return false;
}
std::vector<StreamInfo> streams;
demuxerPluginManager_->SetIsHlsFmp4(false);
streamDemuxer->SetSourceType(mediaSource->GetSourceType());
streamDemuxer->SetInterruptState(false);
streamDemuxer->SetSource(source);
streamDemuxer->Init(MP4_PATH);
Media::Plugins::StreamInfo videoInfo;
videoInfo.streamId = fdp.ConsumeIntegral<int32_t>();
videoInfo.bitRate = fdp.ConsumeIntegral<uint32_t>();
videoInfo.videoWidth = fdp.ConsumeIntegral<int32_t>();
videoInfo.videoHeight = fdp.ConsumeIntegral<int32_t>();
videoInfo.videoType = Media::Plugins::VideoType::VIDEO_TYPE_SDR;
videoInfo.type = OHOS::Media::Plugins::StreamType::VIDEO;
Media::Plugins::StreamInfo audioInfo;
audioInfo.streamId = fdp.ConsumeIntegral<int32_t>();
audioInfo.bitRate = fdp.ConsumeIntegral<uint32_t>();
audioInfo.videoWidth = fdp.ConsumeIntegral<int32_t>();
audioInfo.videoHeight = fdp.ConsumeIntegral<int32_t>();
audioInfo.videoType = Media::Plugins::VideoType::VIDEO_TYPE_SDR;
audioInfo.type = OHOS::Media::Plugins::StreamType::AUDIO;
Media::Plugins::StreamInfo subtitleInfo;
subtitleInfo.streamId = fdp.ConsumeIntegral<int32_t>();
subtitleInfo.type = OHOS::Media::Plugins::StreamType::SUBTITLE;
streams.push_back(videoInfo);
streams.push_back(audioInfo);
streams.push_back(subtitleInfo);
int32_t streamID = fdp.ConsumeIntegral<int32_t>();
int32_t trackId = fdp.ConsumeIntegral<int32_t>();
int32_t innerTrackId = fdp.ConsumeIntegral<int32_t>();
demuxerPluginManager_->InitDefaultPlay(streams);
demuxerPluginManager_->InitDefaultPlay(streams);
demuxerPluginManager_->SetResetEosStatus(fdp.ConsumeBool());
demuxerPluginManager_->GetTrackInfoByStreamID(streamID, trackId, innerTrackId);
if (innerTrackId != trackId) {
return false;
}
TrackType trackType;
switch (fdp.ConsumeIntegral<int32_t>() % SELECT_TRACK) {
case VIDEO_TRACK:
trackType = TrackType::TRACK_VIDEO;
break;
case AUDIO_TRACK:
trackType = TrackType::TRACK_AUDIO;
break;
case SUBTITLE_TRACK:
trackType = TrackType::TRACK_SUBTITLE;
break;
default:
trackType = TrackType::TRACK_INVALID;
break;
}
demuxerPluginManager_->GetTrackInfoByStreamID(streamID, trackId, innerTrackId, trackType);
if (innerTrackId != trackId) {
return false;
}
int32_t innerTrackIndex = demuxerPluginManager_->GetInnerTrackIDByTrackID(trackId);
if (innerTrackIndex != trackId) {
return false;
}
int32_t cusTypeStreamId = demuxerPluginManager_->GetStreamIDByTrackType(trackType);
if (trackType == TRACK_VIDEO) {
if (cusTypeStreamId != videoInfo.streamId) {
return false;
}
} else if (trackType == TRACK_AUDIO) {
if (cusTypeStreamId != audioInfo.streamId) {
return false;
}
} else if (trackType == TRACK_SUBTITLE) {
if (cusTypeStreamId != subtitleInfo.streamId) {
return false;
}
} else {
if (cusTypeStreamId != INVALID_STREAM_OR_TRACK_ID) {
return false;
}
}
demuxerPluginManager_->StopPlugin(streamID, streamDemuxer);
bool isRebooted = false;
demuxerPluginManager_->RebootPlugin(streamID, trackType, streamDemuxer, isRebooted);
int64_t realSeekTime = fdp.ConsumeIntegral<int64_t>();
demuxerPluginManager_->SingleStreamSeekTo(realSeekTime,
Plugins::SeekMode::SEEK_CLOSEST_SYNC, streamID, realSeekTime);
demuxerPluginManager_->Start();
demuxerPluginManager_->Stop();
demuxerPluginManager_->Flush();
demuxerPluginManager_->Reset();
Plugins::MediaInfo mediaInfo;
demuxerPluginManager_->LoadCurrentAllPlugin(streamDemuxer, mediaInfo);
demuxerPluginManager_->GetCurrentBitRate();
demuxerPluginManager_->GetTrackTypeByTrackID(trackId);
demuxerPluginManager_->AddExternalSubtitle();
demuxerPluginManager_->AddExternalSubtitle();
demuxerPluginManager_->SetApiVersion(fdp.ConsumeIntegral<int32_t>());
int ret = remove(MP4_PATH);
if (ret != 0) {
return false;
}
return true;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
OHOS::DemuxerPluginManagerFuzzTest(data, size);
return 0;
}