* 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 <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <cstring>
#include <iostream>
#include <vector>
#include <memory>
#include "demuxer_plugin_manager.h"
#include "stream_demuxer.h"
#include "common/media_source.h"
#include "plugin/plugin_manager_v2.h"
#include "buffer/avbuffer.h"
#include "demuxerpluginflv_sample.h"
using namespace OHOS::Media;
using namespace OHOS::Media::Plugins;
using namespace OHOS::Media::Plugins::Ffmpeg;
namespace OHOS {
namespace Media {
const char* TEST_FILE_PATH = "/data/test/demuxerpluginflvfuzztest.flv";
const int32_t VIDEO_HEIGHT_DEFAULT = 1280;
const int32_t VIDEO_WIDTH_DEFAULT = 720;
const uint32_t INTERFACE_TIMEOUT = 100;
const int64_t SEEK_TIME_DEFAULT = 1000;
DemuxerPluginFlvTest::DemuxerPluginFlvTest() = default;
DemuxerPluginFlvTest::~DemuxerPluginFlvTest()
{
if (fd_ >= 0) {
close(fd_);
}
fd_ = -1;
demuxerPlugin_ = nullptr;
}
bool DemuxerPluginFlvTest::InitWithFlvData(const uint8_t* data, size_t size)
{
if (!data || size == 0) {
return false;
}
fd_ = open(TEST_FILE_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd_ < 0) {
return false;
}
ssize_t len = write(fd_, data, size);
if (len != static_cast<ssize_t>(size)) {
close(fd_);
fd_ = -1;
return false;
}
lseek(fd_, 0, SEEK_SET);
dataSize_ = size;
return true;
}
void DemuxerPluginFlvTest::PrepareDemuxerPlugin(MediaInfo& mediaInfo, size_t& bufferSize, AVBufferWrapper& buffer)
{
std::string uri = "fd://" + std::to_string(fd_) + "?offset=0&size=" + std::to_string(dataSize_);
std::shared_ptr<MediaSource> mediaSource = std::make_shared<MediaSource>(uri);
std::shared_ptr<StreamDemuxer> streamDemuxer = std::make_shared<StreamDemuxer>();
std::shared_ptr<Source> source = std::make_shared<Source>();
source->SetSource(mediaSource);
streamDemuxer->SetSource(source);
streamDemuxer->SetSourceType(mediaSource->GetSourceType());
streamDemuxer->Init(uri);
streamDemuxer->SetDemuxerState(0, DemuxerState::DEMUXER_STATE_PARSE_FRAME);
auto dataSource = std::make_shared<DataSourceImpl>(streamDemuxer, 0);
auto basePlugin = PluginManagerV2::Instance().CreatePluginByName("avdemux_flv");
demuxerPlugin_ = std::reinterpret_pointer_cast<FFmpegDemuxerPlugin>(basePlugin);
if (!demuxerPlugin_) {
return;
}
if (demuxerPlugin_->SetDataSource(dataSource) != Status::OK) {
demuxerPlugin_ = nullptr;
return;
}
if (demuxerPlugin_->GetMediaInfo(mediaInfo) != Status::OK) {
demuxerPlugin_ = nullptr;
return;
}
int32_t width = VIDEO_WIDTH_DEFAULT;
int32_t height = VIDEO_HEIGHT_DEFAULT;
for (const auto& track : mediaInfo.tracks) {
int32_t w = 0;
int32_t h = 0;
track.GetData(Tag::VIDEO_WIDTH, w);
track.GetData(Tag::VIDEO_HEIGHT, h);
if (w > 0 && h > 0) {
width = w;
height = h;
break;
}
}
bufferSize = width * height * 3;
buffer = AVBufferWrapper(bufferSize);
}
void DemuxerPluginFlvTest::OperateDemuxerPlugin(MediaInfo& mediaInfo, size_t bufferSize, AVBufferWrapper& buffer)
{
for (uint32_t idx = 0; idx < mediaInfo.tracks.size(); ++idx) {
demuxerPlugin_->SelectTrack(idx);
}
for (uint32_t idx = 0; idx < mediaInfo.tracks.size(); ++idx) {
demuxerPlugin_->UnselectTrack(idx);
}
for (uint32_t idx = 0; idx < mediaInfo.tracks.size(); ++idx) {
demuxerPlugin_->SelectTrack(idx);
}
demuxerPlugin_->BoostReadThreadPriority();
for (uint32_t idx = 0; idx < mediaInfo.tracks.size(); ++idx) {
demuxerPlugin_->ReadSample(idx, buffer.mediaAVBuffer, INTERFACE_TIMEOUT);
demuxerPlugin_->ReadSample(idx, buffer.mediaAVBuffer);
int32_t nextSampleSize = 0;
int64_t pts = 0;
demuxerPlugin_->GetNextSampleSize(idx, nextSampleSize, INTERFACE_TIMEOUT);
demuxerPlugin_->GetLastPTSByTrackId(idx, pts);
demuxerPlugin_->Pause();
}
int64_t seekTime = 0;
demuxerPlugin_->SeekTo(-1, 0, SeekMode::SEEK_NEXT_SYNC, seekTime);
demuxerPlugin_->Flush();
demuxerPlugin_->SeekTo(0, SEEK_TIME_DEFAULT, SeekMode::SEEK_PREVIOUS_SYNC, seekTime);
demuxerPlugin_->Reset();
}
void DemuxerPluginFlvTest::RunDemuxerInterfaceFuzz()
{
if (fd_ < 0) {
return;
}
MediaInfo mediaInfo;
size_t bufferSize = 0;
AVBufferWrapper buffer(1);
PrepareDemuxerPlugin(mediaInfo, bufferSize, buffer);
if (!demuxerPlugin_) {
return;
}
OperateDemuxerPlugin(mediaInfo, bufferSize, buffer);
}
}
}