* Copyright (C) 2024 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 <cinttypes>
#include <cstdio>
#include <fcntl.h>
#include <iostream>
#include <malloc.h>
#include <string>
#include <thread>
#include <sys/stat.h>
#include <fstream>
#include <ctime>
#include "native_avbuffer.h"
#include "inner_demuxer_sample.h"
#include "native_avcodec_base.h"
#include "meta/format.h"
#include "avcodec_errors.h"
#include "avcodec_common.h"
#include "native_avformat.h"
#include "av_common.h"
#include <random>
#include "avmuxer.h"
#include "media_description.h"
using namespace std;
using namespace OHOS::MediaAVCodec;
using namespace OHOS::Media;
namespace OHOS {
namespace MediaAVCodec {
InnerDemuxerSample::InnerDemuxerSample()
{
}
InnerDemuxerSample::~InnerDemuxerSample()
{
if (fd > 0) {
close(fd);
fd = -1;
}
}
bool InnerDemuxerSample::CreateBuffer()
{
uint32_t buffersize = 1024 * 1024;
std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
if (!avBuffer) {
return false;
}
return true;
}
int32_t InnerDemuxerSample::InitWithFile(const std::string &path, bool local)
{
if (local) {
fd = open(path.c_str(), O_RDONLY);
int64_t size = GetFileSize(path);
this->avsource_ = AVSourceFactory::CreateWithFD(fd, 0, size);
} else {
this->avsource_ = AVSourceFactory::CreateWithURI(const_cast<char*>(path.data()));
}
if (!avsource_) {
return -1;
}
this->demuxer_ = AVDemuxerFactory::CreateWithSource(avsource_);
if (!demuxer_) {
return -1;
}
int32_t ret = this->avsource_->GetSourceFormat(source_format_);
if (ret != 0) {
printf("GetSourceFormat is failed\n");
return ret;
}
source_format_.GetIntValue(OH_MD_KEY_TRACK_COUNT, trackCount);
source_format_.GetLongValue(OH_MD_KEY_DURATION, duration);
printf("====>total tracks:%d duration:%" PRId64 "\n", trackCount, duration);
for (int32_t i = 0; i < trackCount; i++) {
int32_t trackType = -1;
ret = this->avsource_->GetTrackFormat(track_format_, i);
if (ret != 0) {
return ret;
}
track_format_.GetIntValue(OH_MD_KEY_TRACK_TYPE, trackType);
if (trackType == MEDIA_TYPE_VID) {
GetHdrType();
videoIsEnd = false;
videoTrackIdx = i;
} else {
audioIsEnd = false;
}
if (unSelectTrack != i && (trackType == MEDIA_TYPE_VID || trackType == MEDIA_TYPE_AUD ||
trackType == MEDIA_TYPE_SUBTITLE || trackType == MEDIA_TYPE_TIMED_METADATA ||
trackType == MEDIA_TYPE_AUXILIARY)) {
ret = this->demuxer_->SelectTrackByID(i);
if (ret != 0) {
printf("SelectTrackByID is failed\n");
return ret;
}
}
}
return ret;
}
void InnerDemuxerSample::GetHdrType()
{
if (!track_format_.GetIntValue(Media::Tag::VIDEO_HDR_TYPE, hdrType)) {
cout << "get hdr type failed" << endl;
getHdrMetadata = false;
}
}
int32_t InnerDemuxerSample::ReadSampleAndSave()
{
uint32_t buffersize = 1024 * 1024;
std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
while (!isAudioEosFlagForSave && !isVideoEosFlagForSave) {
CheckLoopForSave();
}
videoIndexPtsList.sort();
audioIndexPtsList.sort();
return retForSave;
}
void InnerDemuxerSample::CheckLoopForSave()
{
for (int32_t i = 0; i < trackCount; i++) {
retForSave = this->demuxer_->ReadSampleBuffer(i, avBuffer);
if (retForSave != 0) {
cout << "ReadSampleBuffer fail ret:" << retForSave << endl;
isVideoEosFlagForSave = true;
isAudioEosFlagForSave = true;
break;
}
if (avBuffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
if (i == videoTrackIdx) {
isVideoEosFlagForSave = true;
} else {
isAudioEosFlagForSave = true;
}
continue;
}
if (i == videoTrackIdx) {
videoIndexPtsList.push_back(avBuffer->pts_);
videoIndexForRead ++;
if (videoIndexForRead == 1) {
videoPtsOffset = avBuffer->pts_;
}
} else {
audioIndexPtsList.push_back(avBuffer->pts_);
audioIndexForRead ++;
if (audioIndexForRead == 1) {
audioPtsOffset = avBuffer->pts_;
}
}
}
}
int32_t InnerDemuxerSample::CheckPtsFromIndex()
{
int32_t num = 999;
for (int32_t i = 0; i < trackCount; i++) {
if (retForPts == num) {
break;
}
indexForPts = 0;
CheckLoopForPtsFromIndex(i);
}
cout << "CheckPtsFromIndex ret:" << retForPts << endl;
return retForPts;
}
int32_t InnerDemuxerSample::CheckIndexFromPts()
{
int32_t num = 999;
for (int32_t i = 0; i < trackCount; i++) {
if (retForIndex == num) {
break;
}
listIndex = 0;
previousValue = 0;
CheckLoopForIndexFromPts(i);
}
cout << "CheckIndexFromPts ret:" << retForIndex << endl;
return retForIndex;
}
void InnerDemuxerSample::CheckLoopForPtsFromIndex(int32_t trackIndex)
{
uint64_t presentationTimeUs = 0;
int32_t num = 999;
if (trackIndex == videoTrackIdx) {
for (const auto &pair : videoIndexPtsList) {
retForPts = demuxer_->GetRelativePresentationTimeUsByIndex(trackIndex, indexForPts, presentationTimeUs);
if (retForPts != 0) {
cout << "GetRelativePresentationTimeUsByIndex fail ret:" << retForPts << endl;
break;
}
if (!((pair - videoPtsOffset - 1) <= presentationTimeUs <= (pair - videoPtsOffset + 1))) {
retForPts = num;
break;
}
indexForPts ++;
}
} else {
for (const auto &pair : audioIndexPtsList) {
retForPts = demuxer_->GetRelativePresentationTimeUsByIndex(trackIndex, indexForPts, presentationTimeUs);
if (retForPts != 0) {
cout << "GetRelativePresentationTimeUsByIndex fail ret:" << retForPts << endl;
break;
}
if (!((pair - audioPtsOffset - 1) <= presentationTimeUs <= (pair - audioPtsOffset + 1))) {
retForPts = num;
break;
}
indexForPts ++;
}
}
}
void InnerDemuxerSample::CheckLoopForIndexFromPts(int32_t trackIndex)
{
if (trackIndex == videoTrackIdx) {
GetIndexByPtsForVideo(trackIndex);
} else {
GetIndexByPtsForAudio(trackIndex);
}
}
void InnerDemuxerSample::GetIndexByPtsForVideo(int32_t trackIndex)
{
int division = 2;
int value = 1;
for (const auto &pair : videoIndexPtsList) {
uint64_t tempValue = pair;
uint64_t relativePresentationTimeUs = static_cast<uint64_t>(pair - videoPtsOffset);
GetIndexFromPtsForVideo(trackIndex, relativePresentationTimeUs, pair, division, value);
if (retForIndex != 0) {
cout << "video GetIndexByRelativePresentationTimeUs fail ret:" << retForIndex << endl;
break;
}
retForIndex = CheckIndex(indexVideo);
if (retForIndex != 0) {
break;
}
previousValue = tempValue;
listIndex ++;
}
}
void InnerDemuxerSample::GetIndexByPtsForAudio(int32_t trackIndex)
{
int division = 2;
int value = 1;
for (const auto &pair : audioIndexPtsList) {
uint64_t tempValue = pair;
uint64_t relativePresentationTimeUs = static_cast<uint64_t>(pair - audioPtsOffset);
GetIndexFromPtsForAudio(trackIndex, relativePresentationTimeUs, pair, division, value);
if (retForIndex != 0) {
cout << "audio GetIndexByRelativePresentationTimeUs fail ret:" << retForIndex << endl;
break;
}
retForIndex = CheckIndex(indexAudio);
if (retForIndex != 0) {
break;
}
previousValue = tempValue;
listIndex ++;
}
}
void InnerDemuxerSample::GetIndexFromPtsForVideo(int32_t trackIndex,
uint64_t relativePresentationTimeUs, int64_t pair, int division, int value)
{
if (isPtsExist && listIndex != 0) {
if (isPtsCloseLeft) {
if (division != 0) {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs - ((pair - previousValue) / division + value), indexVideo);
}
} else if (isPtsCloseCenter) {
if (division != 0) {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs - ((pair - previousValue) / division), indexVideo);
}
} else {
if (division != 0) {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs - ((pair - previousValue) / division - value), indexVideo);
}
}
} else {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs, indexVideo);
}
}
void InnerDemuxerSample::GetIndexFromPtsForAudio(int32_t trackIndex,
uint64_t relativePresentationTimeUs, int64_t pair, int division, int value)
{
if (isPtsExist && listIndex != 0) {
if (isPtsCloseLeft) {
if (division != 0) {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs - ((pair - previousValue) / division + value), indexAudio);
}
} else if (isPtsCloseCenter) {
if (division != 0) {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs - ((pair - previousValue) / division), indexAudio);
}
} else {
if (division != 0) {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs - ((pair - previousValue) / division - value), indexAudio);
}
}
} else {
retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
relativePresentationTimeUs, indexAudio);
}
}
int32_t InnerDemuxerSample::CheckIndex(uint32_t index)
{
int32_t num = 999;
if (isPtsExist) {
if (isPtsCloseLeft && listIndex != 0) {
if (index != (listIndex -1)) {
retForIndex = num;
cout << "pts != pair index:" << index << " listIndex - 1 :"<< (listIndex - 1) << endl;
}
} else if (isPtsCloseCenter && listIndex != 0) {
if (index != listIndex && index != (listIndex - 1)) {
retForIndex = num;
cout << "pts != pair index:" << index << " listIndex - 1 :"<< (listIndex - 1) << endl;
}
} else {
if (index != listIndex) {
retForIndex = num;
cout << "pts != pair index:" << index << " listIndex:"<< listIndex << endl;
}
}
} else {
if (index != listIndex) {
retForIndex = num;
cout << "pts != pair index:" << index << " listIndex:"<< listIndex << endl;
}
}
return retForIndex;
}
int32_t InnerDemuxerSample::CheckHasTimedMeta()
{
int32_t hasMeta = 0;
source_format_.GetIntValue(AVSourceFormat::SOURCE_HAS_TIMEDMETA, hasMeta);
return hasMeta;
}
int32_t InnerDemuxerSample::CheckTimedMetaFormat(int32_t trackIndex, int32_t srcTrackIndex)
{
int32_t ret = this->avsource_->GetTrackFormat(track_format_, trackIndex);
if (ret != 0) {
cout << "get track_format_ fail" << endl;
return -1;
}
int32_t trackType = 0;
std::string codecMime = "";
std::string timedMetadataKey = "";
int32_t srcTrackID = -1;
std::string TIMED_METADATA_KEY = "com.openharmony.timed_metadata.test";
track_format_.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackType);
if (trackType != MediaType::MEDIA_TYPE_TIMED_METADATA) {
cout << "check MD_KEY_TRACK_TYPE fail" << endl;
return -1;
}
track_format_.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, codecMime);
if (codecMime != "meta/timed-metadata") {
cout << "check codecMime fail" << endl;
return -1;
}
track_format_.GetStringValue(MediaDescriptionKey::MD_KEY_TIMED_METADATA_KEY, timedMetadataKey);
if (timedMetadataKey != TIMED_METADATA_KEY) {
cout << "check MD_KEY_TIMED_METADATA_KEY fail" << endl;
return -1;
}
track_format_.GetIntValue(MediaDescriptionKey::MD_KEY_TIMED_METADATA_SRC_TRACK_ID, srcTrackID);
if (srcTrackID != srcTrackIndex) {
cout << "check MD_KEY_TIMED_METADATA_SRC_TRACK_ID fail" << endl;
return -1;
}
return 0;
}
int32_t InnerDemuxerSample::CheckTimedMeta(int32_t metaTrack)
{
uint32_t buffersize = 1024 * 1024;
std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
uint32_t twoHundredAndTen = 210;
while (!isVideoEosFlagForMeta && !isMetaEosFlagForMeta && retForMeta == 0) {
CheckLoop(metaTrack);
}
if (videoIndexForMeta != twoHundredAndTen || metaIndexForMeta != twoHundredAndTen) {
retForMeta = -1;
}
return retForMeta;
}
void InnerDemuxerSample::CheckLoop(int32_t metaTrack)
{
int32_t compaseSize = 0;
int32_t metaSize = 0;
for (int32_t i = 0; i < trackCount; i++) {
retForMeta = this->demuxer_->ReadSampleBuffer(i, avBuffer);
if (retForMeta != 0) {
isVideoEosFlagForMeta = true;
isMetaEosFlagForMeta = true;
break;
}
if (avBuffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
if (i == videoTrackIdx) {
isVideoEosFlagForMeta = true;
} else if (i == metaTrack) {
isMetaEosFlagForMeta = true;
}
continue;
}
if (i == videoTrackIdx) {
compaseSize = static_cast<int32_t>(avBuffer->memory_->GetSize());
if (metaTrack == 0 && metaSize != compaseSize - 1) {
retForMeta = -1;
break;
}
videoIndexForMeta ++;
} else if (i == metaTrack) {
metaSize = static_cast<int32_t>(avBuffer->memory_->GetSize());
if (metaTrack != 0 && metaSize != compaseSize - 1) {
retForMeta = -1;
break;
}
metaIndexForMeta ++;
}
}
}
size_t InnerDemuxerSample::GetFileSize(const std::string& filePath)
{
size_t fileSize = 0;
if (!filePath.empty()) {
struct stat fileStatus {};
if (stat(filePath.c_str(), &fileStatus) == 0) {
fileSize = static_cast<size_t>(fileStatus.st_size);
}
}
return fileSize;
}
bool InnerDemuxerSample::CheckDemuxer(int32_t &readMax)
{
for (int32_t i = 0; i < trackCount; i++) {
int32_t ret = this->demuxer_->SelectTrackByID(i);
if (ret != 0) {
printf("SelectTrackByID is failed\n");
return false;
}
ret = this->demuxer_->ReadSampleBuffer(i, avBuffer);
if (ret != 0) {
cout << "ReadSampleBuffer fail ret:" << ret << endl;
isAudioEosFlagForSave = true;
return false;
}
if (avBuffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
printf("ReadSampleBuffer EOS\n");
isAudioEosFlagForSave = true;
continue;
}
if (avBuffer->memory_->GetSize() > readMax) {
readMax = avBuffer->memory_->GetSize();
}
}
return true;
}
bool InnerDemuxerSample::CheckApeSourceData(const std::string &path, int32_t version)
{
fd = open(path.c_str(), O_RDONLY);
int64_t size = GetFileSize(path);
this->avsource_ = AVSourceFactory::CreateWithFD(fd, 0, size);
if (!avsource_) {
printf("Source is null\n");
return false;
}
this->demuxer_ = AVDemuxerFactory::CreateWithSource(avsource_);
if (!demuxer_) {
printf("AVDemuxerFactory::CreateWithSource is failed\n");
return false;
}
int32_t ret = this->avsource_->GetSourceFormat(source_format_);
if (ret != 0) {
return false;
}
source_format_.GetIntValue(OH_MD_KEY_TRACK_COUNT, trackCount);
uint32_t buffersize = 2048 * 2048;
std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
int32_t trackType = 0;
int32_t readSize = 0;
int32_t frame = 0;
int32_t sizeMax = 0;
ret = this->avsource_->GetTrackFormat(track_format_, 0);
if (ret != 0) {
return false;
}
track_format_.GetIntValue(Media::Tag::AUDIO_SAMPLE_PER_FRAME, frame);
track_format_.GetIntValue(Media::Tag::AUDIO_MAX_INPUT_SIZE, sizeMax);
track_format_.GetIntValue(OH_MD_KEY_TRACK_TYPE, trackType);
if (trackType != MEDIA_TYPE_AUD) {
return false;
}
while (!isAudioEosFlagForSave) {
if (!CheckDemuxer(readSize)) {
return false;
}
}
if (frame != version) {
printf("frame not as expected\n");
return false;
}
if (sizeMax != readSize) {
printf("sizeMax = %d not as expected\n", sizeMax);
return false;
}
return true;
}
bool InnerDemuxerSample::CheckCache(std::vector<std::vector<int32_t>> &cacheCheckSteps, int32_t times)
{
uint32_t memoryUsage = 0;
for (auto step : cacheCheckSteps) {
demuxer_->GetCurrentCacheSize(step[0], memoryUsage);
if (memoryUsage != step[times]) {
return false;
}
}
return true;
}
bool InnerDemuxerSample::ReadVideo(std::vector<std::vector<int32_t>> &cacheCheckSteps)
{
int32_t readCount = 0;
int32_t ret = 0;
int32_t checkVector1 = 1;
int32_t checkVector2 = 2;
bool isEnd = true;
while (isEnd) {
if (readCount >= readPos) {
isEnd = false;
if (!CheckCache(cacheCheckSteps, checkVector1)) {
return false;
}
ret = demuxer_->ReadSampleBuffer(indexAud, avBuffer);
if (ret != 0) {
cout << "ReadSampleBuffer fail ret:" << ret << endl;
return false;
}
if (!CheckCache(cacheCheckSteps, checkVector2)) {
return false;
}
break;
} else {
readCount++;
ret = demuxer_->ReadSampleBuffer(indexVid, avBuffer);
if (ret != 0) {
cout << "ReadSampleBuffer fail ret:" << ret << endl;
isEnd = false;
return false;
}
}
}
return true;
}
bool InnerDemuxerSample::ReadAudio(std::vector<std::vector<int32_t>> &cacheCheckSteps)
{
int32_t readCount = 0;
int32_t ret = 0;
int32_t checkVector1 = 1;
int32_t checkVector2 = 2;
bool isEnd = true;
while (isEnd) {
if (readCount >= readPos) {
isEnd = false;
if (!CheckCache(cacheCheckSteps, checkVector1)) {
return false;
}
ret = demuxer_->ReadSampleBuffer(indexVid, avBuffer);
if (ret != 0) {
cout << "ReadSampleBuffer fail ret:" << ret << endl;
return false;
}
if (!CheckCache(cacheCheckSteps, checkVector2)) {
return false;
}
break;
} else {
readCount++;
ret = demuxer_->ReadSampleBuffer(indexAud, avBuffer);
if (ret != 0) {
cout << "ReadSampleBuffer fail ret:" << ret << endl;
isEnd = false;
return false;
}
}
}
return true;
}
int32_t InnerDemuxerSample::ReadSample(int32_t videoFrame, int32_t audioFrame)
{
int32_t ret = 0;
uint32_t buffersize = 1024 * 1024;
std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
while (!audioIsEnd || !videoIsEnd) {
for (int32_t i = 0; i < trackCount; i++) {
int32_t trackType = -1;
ret = this->avsource_->GetTrackFormat(track_format_, i);
if (ret != 0) {
printf("GetTrackFormat is failed\n");
return ret;
}
track_format_.GetIntValue(OH_MD_KEY_TRACK_TYPE, trackType);
if ((audioIsEnd && (trackType == MEDIA_TYPE_AUD)) || (videoIsEnd && (trackType == MEDIA_TYPE_VID))) {
continue;
}
if (!(trackType == MEDIA_TYPE_VID || trackType == MEDIA_TYPE_AUD ||
trackType == MEDIA_TYPE_SUBTITLE || trackType == MEDIA_TYPE_TIMED_METADATA ||
trackType == MEDIA_TYPE_AUXILIARY)) {
continue;
}
ret = this->demuxer_->ReadSampleBuffer(i, avBuffer);
if (ret != 0) {
cout << "ReadSampleBuffer fail ret:" << retForSave << endl;
break;
}
if (SetEos(trackType) != 0) {
continue;
}
if (trackType == MEDIA_TYPE_VID) {
videoIndexForRead ++;
} else {
audioIndexForRead ++;
}
}
}
if (videoIndexForRead != videoFrame || audioIndexForRead != audioFrame) {
return -1;
}
return ret;
}
int32_t InnerDemuxerSample::SetEos(int32_t trackType)
{
if (avBuffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
if (trackType == MEDIA_TYPE_VID) {
videoIsEnd = true;
} else {
audioIsEnd = true;
}
return -1;
}
return 0;
}
}
}