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