1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "reference_parser_demo.h"
17 #include <cstdio>
18 #include <string>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <iostream>
22 #include <fstream>
23 #include "media_description.h"
24 
25 using namespace std;
26 
27 using json = nlohmann::json;
28 
29 namespace {
30 constexpr const char *SOURCE_DIR = "/data/test/media/";
31 constexpr uint32_t MAX_SCENE_NUM = static_cast<uint32_t>(OHOS::MediaAVCodec::MP4Scene::SCENE_MAX);
32 constexpr const char *VIDEO_FILE_NAME[MAX_SCENE_NUM] = {
33     "ipb_0", "ipb_1", "ippp_0", "ippp_1", "ippp_scala_0", "ippp_scala_1", "sdtp", "sdtp_ext"};
34 constexpr int32_t MAX_BUFFER_SIZE = 8294400;
35 constexpr int32_t MILL_TO_MICRO = 1000;
36 constexpr uint32_t MIN_REMAIN_LAYERS = 2;
37 } // namespace
38 
from_json(const nlohmann::json & j,JsonGopInfo & gop)39 void from_json(const nlohmann::json &j, JsonGopInfo &gop)
40 {
41     j.at("gopId").get_to(gop.gopId);
42     j.at("gopSize").get_to(gop.gopSize);
43     j.at("startFrameId").get_to(gop.startFrameId);
44 }
45 
from_json(const nlohmann::json & j,JsonFrameLayerInfo & frame)46 void from_json(const nlohmann::json &j, JsonFrameLayerInfo &frame)
47 {
48     j.at("frameId").get_to(frame.frameId);
49     j.at("dts").get_to(frame.dts);
50     j.at("layer").get_to(frame.layer);
51     j.at("discardable").get_to(frame.discardable);
52 }
53 
54 namespace OHOS {
55 namespace MediaAVCodec {
56 using namespace Media;
57 
~ReferenceParserDemo()58 ReferenceParserDemo::~ReferenceParserDemo()
59 {
60     close(fd_);
61     fd_ = 0;
62     source_ = nullptr;
63     demuxer_ = nullptr;
64 }
65 
InitScene(MP4Scene scene)66 int32_t ReferenceParserDemo::InitScene(MP4Scene scene)
67 {
68     string path = string(SOURCE_DIR) + string(VIDEO_FILE_NAME[static_cast<uint32_t>(scene)]);
69     std::ifstream(path + "_gop.json") >> gopJson_;
70     std::ifstream(path + "_frame.json") >> frameLayerJson_;
71     string filePath = path + ".mp4";
72     fd_ = open(filePath.c_str(), O_RDONLY);
73     struct stat fileStatus {};
74     if (stat(filePath.c_str(), &fileStatus) != 0) {
75         return -1;
76     }
77     int64_t size = static_cast<int64_t>(fileStatus.st_size);
78     cout << filePath << ", fd is " << fd_ << ", size is " << size << endl;
79     int32_t ret = InitDemuxer(size);
80     if (ret < 0) {
81         cout << "InitDemuxer failed!" << endl;
82         return ret;
83     }
84     LoadJson();
85     shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
86     buffer_ = AVBuffer::CreateAVBuffer(allocator, MAX_BUFFER_SIZE);
87     return 0;
88 }
89 
InitDemuxer(int64_t size)90 int32_t ReferenceParserDemo::InitDemuxer(int64_t size)
91 {
92     source_ = AVSourceFactory::CreateWithFD(fd_, 0, size);
93     if (source_ == nullptr) {
94         cout << "CreatWithFD failed!" << endl;
95         return -1;
96     }
97     Format format;
98     source_->GetSourceFormat(format);
99     int32_t trackCount = 0;
100     format.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_COUNT, trackCount);
101     for (auto i = 0; i < trackCount; i++) {
102         source_->GetTrackFormat(format, i);
103         int32_t trackType = 0;
104         format.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackType);
105         if (trackType == 1) {
106             videoTrackId_ = i;
107         }
108     }
109     demuxer_ = AVDemuxerFactory::CreateWithSource(source_);
110     if (demuxer_ == nullptr) {
111         cout << "CreateWithSource failed!" << endl;
112         return -1;
113     }
114     return 0;
115 }
116 
LoadJson()117 void ReferenceParserDemo::LoadJson()
118 {
119     gopVec_ = gopJson_.get<vector<JsonGopInfo>>();
120     frameVec_ = frameLayerJson_.get<vector<JsonFrameLayerInfo>>();
121     for (auto gop : gopVec_) {
122         cout << "GopID " << gop.gopId << ", GopSize " << gop.gopSize << ", startFrameId " << gop.startFrameId << endl;
123         int32_t frameId = gop.startFrameId;
124         for (auto i = 0; i < gop.gopSize; i++) {
125             JsonFrameLayerInfo frame = frameVec_[frameId + i];
126             frameMap_.emplace(frame.dts, frame);
127             cout << "FrameId " << frame.frameId << ", Layer " << frame.layer << endl;
128         }
129     }
130 }
131 
SetDecIntervalMs(int64_t decIntervalMs)132 void ReferenceParserDemo::SetDecIntervalMs(int64_t decIntervalMs)
133 {
134     decIntervalUs_ = decIntervalMs * MILL_TO_MICRO;
135 }
136 
CheckFrameLayerResult(const FrameLayerInfo & info,int64_t dts)137 bool ReferenceParserDemo::CheckFrameLayerResult(const FrameLayerInfo &info, int64_t dts)
138 {
139     JsonFrameLayerInfo frame = frameMap_[dts];
140     if (!frame.discardable && info.isDiscardable) {
141         cout << "FrameId " << frame.frameId << ", expect layer " << frame.layer << ", get layer " << info.layer
142              << ", dts " << dts << ", match failed!" << endl;
143         return false;
144     }
145     cout << "FrameId " << frame.frameId << ", dts" << dts << ", match success!" << endl;
146     return true;
147 }
148 
CheckGopLayerResult(GopLayerInfo & GopLayerInfo,uint32_t gopid)149 bool ReferenceParserDemo::CheckGopLayerResult(GopLayerInfo &GopLayerInfo, uint32_t gopid)
150 {
151     return true;
152 }
153 
GetMaxDiscardLayer(const GopLayerInfo & GopLayerInfo)154 int32_t ReferenceParserDemo::GetMaxDiscardLayer(const GopLayerInfo &GopLayerInfo)
155 {
156     return GopLayerInfo.layerCount - 1 - MIN_REMAIN_LAYERS;
157 }
158 
DoAccurateSeek(int64_t seekTimeMs)159 bool ReferenceParserDemo::DoAccurateSeek(int64_t seekTimeMs)
160 {
161     demuxer_->SelectTrackByID(videoTrackId_);
162     demuxer_->ReadSampleBuffer(videoTrackId_, buffer_);
163     demuxer_->SeekToTime(seekTimeMs, SeekMode::SEEK_PREVIOUS_SYNC);
164     demuxer_->StartReferenceParser(seekTimeMs);
165     FrameLayerInfo frameInfo;
166     int64_t pts = -1L;
167     while (pts < seekTimeMs * MILL_TO_MICRO) {
168         demuxer_->ReadSampleBuffer(videoTrackId_, buffer_);
169         if (buffer_->flag_ & AVCODEC_BUFFER_FLAG_EOS) {
170             break;
171         }
172         demuxer_->GetFrameLayerInfo(buffer_, frameInfo);
173         pts = buffer_->pts_;
174         if (!frameInfo.isDiscardable) {
175             usleep(decIntervalUs_);
176         }
177         if (!CheckFrameLayerResult(frameInfo, buffer_->dts_)) {
178             return false;
179         }
180     }
181     return true;
182 }
183 
IsFrameDiscard(FrameLayerInfo & frameInfo,bool & isDiscard)184 int32_t ReferenceParserDemo::IsFrameDiscard(FrameLayerInfo &frameInfo, bool &isDiscard)
185 {
186     if (frameInfo.layer == -1) {
187         isDiscard = frameInfo.isDiscardable;
188         return 0;
189     }
190 
191     if (checkedGopId_ != frameInfo.gopId) {
192         GopLayerInfo gopLayerInfo;
193         demuxer_->GetGopLayerInfo(frameInfo.gopId, gopLayerInfo);
194         if (!CheckGopLayerResult(gopLayerInfo, frameInfo.gopId)) {
195             return -1;
196         }
197         checkedGopId_ = frameInfo.gopId;
198         maxDiscardLayer_ = GetMaxDiscardLayer(gopLayerInfo);
199     }
200     isDiscard = frameInfo.layer <= maxDiscardLayer_;
201     return 0;
202 }
203 
DoVariableSpeedPlay(int64_t playTimeMs)204 bool ReferenceParserDemo::DoVariableSpeedPlay(int64_t playTimeMs)
205 {
206     demuxer_->SelectTrackByID(videoTrackId_);
207     demuxer_->SeekToTime(playTimeMs, SeekMode::SEEK_PREVIOUS_SYNC);
208     buffer_->pts_ = -1L;
209     while (buffer_->pts_ < playTimeMs * MILL_TO_MICRO) {
210         demuxer_->ReadSampleBuffer(videoTrackId_, buffer_);
211     }
212 
213     demuxer_->StartReferenceParser(playTimeMs);
214     FrameLayerInfo frameInfo;
215     do {
216         demuxer_->ReadSampleBuffer(videoTrackId_, buffer_);
217         demuxer_->GetFrameLayerInfo(buffer_, frameInfo);
218         if (!CheckFrameLayerResult(frameInfo, buffer_->dts_)) {
219             return false;
220         }
221 
222         if (IsFrameDiscard(frameInfo, isDiscard_) != 0) {
223             return false;
224         }
225 
226         if (!isDiscard_) {
227             usleep(decIntervalUs_);
228         }
229     } while (!(buffer_->flag_ & AVCODEC_BUFFER_FLAG_EOS));
230     return true;
231 }
232 
233 } // namespace MediaAVCodec
234 } // namespace OHOS