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 #include "avcodec_e2e_demo_api10.h"
16 
17 #include <iostream>
18 #include <string>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <list>
23 #include "av_common.h"
24 #include "avcodec_common.h"
25 #include "avcodec_errors.h"
26 #include "native_avcodec_videodecoder.h"
27 #include "native_avcodec_videoencoder.h"
28 #include "media_description.h"
29 #include "native_avformat.h"
30 #include "native_avcodec_base.h"
31 
32 using namespace OHOS;
33 using namespace OHOS::MediaAVCodec;
34 using namespace OHOS::MediaAVCodec::E2EDemo;
35 using namespace std;
36 constexpr int64_t MICRO_IN_SECOND = 1000000L;
37 constexpr int32_t AUDIO_BUFFER_SIZE = 1024 * 1024;
38 constexpr float FRAME_INTERVAL_TIMES = 1.5;
39 constexpr double DEFAULT_FRAME_RATE = 25.0;
40 typedef struct FrameInfo {
41     uint32_t index;
42     int32_t pts;
43 }FrameInfo;
44 static list<FrameInfo> frameList;
45 
FrameCompare(const FrameInfo & f1,const FrameInfo & f2)46 static bool FrameCompare(const FrameInfo &f1, const FrameInfo &f2)
47 {
48     return f1.pts < f2.pts;
49 }
50 
GetFileSize(const char * fileName)51 static int64_t GetFileSize(const char *fileName)
52 {
53     int64_t fileSize = 0;
54     if (fileName != nullptr) {
55         struct stat fileStatus {};
56         if (stat(fileName, &fileStatus) == 0) {
57             fileSize = static_cast<int64_t>(fileStatus.st_size);
58         }
59     }
60     return fileSize;
61 }
62 
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)63 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
64 {
65     (void)codec;
66     (void)userData;
67     cout<<"error :"<<errorCode<<endl;
68 }
69 
OnDecStreamChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)70 static void OnDecStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
71 {
72     (void)codec;
73     (void)format;
74     (void)userData;
75 }
76 
OnDecInputDataAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)77 static void OnDecInputDataAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
78 {
79     AVCodecE2EDemoAPI10 *demo = static_cast<AVCodecE2EDemoAPI10*>(userData);
80     OH_AVCodecBufferAttr info;
81     OH_AVDemuxer_ReadSample(demo->demuxer, demo->videoTrackID, data, &info);
82     OH_VideoDecoder_PushInputData(codec, index, info);
83 }
84 
sortFrame(OH_AVCodec * codec,uint32_t index,int32_t pts,uint32_t duration)85 static void sortFrame(OH_AVCodec *codec, uint32_t index, int32_t pts, uint32_t duration)
86 {
87     FrameInfo info = {index, pts};
88     frameList.emplace_back(info);
89     if (frameList.size() > 1) {
90         frameList.sort(FrameCompare);
91         FrameInfo first = frameList.front();
92         auto it = frameList.begin();
93         FrameInfo second = *(++it);
94         if (second.pts - first.pts <= (duration * FRAME_INTERVAL_TIMES)) {
95             OH_VideoDecoder_RenderOutputData(codec, first.index);
96             frameList.pop_front();
97         }
98     }
99 }
100 
OnDecOutputDataAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)101 static void OnDecOutputDataAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data,
102                                      OH_AVCodecBufferAttr *attr, void *userData)
103 {
104     AVCodecE2EDemoAPI10 *demo = static_cast<AVCodecE2EDemoAPI10*>(userData);
105     if (attr->flags & AVCODEC_BUFFER_FLAGS_EOS) {
106         frameList.sort(FrameCompare);
107         while (frameList.size() > 0) {
108             FrameInfo first = frameList.front();
109             OH_VideoDecoder_RenderOutputData(codec, first.index);
110             frameList.pop_front();
111         }
112         OH_VideoEncoder_NotifyEndOfStream(demo->enc);
113         return;
114     }
115     sortFrame(codec, index, attr->pts, demo->frameDuration);
116 }
117 
OnEncStreamChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)118 static void OnEncStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
119 {
120     cout<<"format changed"<<endl;
121 }
122 
OnEncInputDataAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)123 static void OnEncInputDataAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
124 {
125     (void)codec;
126     (void)index;
127     (void)data;
128     (void)userData;
129 }
130 
OnEncOutputDataAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)131 static void OnEncOutputDataAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data,
132                                      OH_AVCodecBufferAttr *attr, void *userData)
133 {
134     AVCodecE2EDemoAPI10 *demo = static_cast<AVCodecE2EDemoAPI10*>(userData);
135     if (attr->flags & AVCODEC_BUFFER_FLAGS_EOS) {
136         demo->isFinish.store(true);
137         demo->waitCond.notify_all();
138         return;
139     }
140     OH_AVMuxer_WriteSample(demo->muxer, demo->videoTrackID, data, *attr);
141     OH_VideoDecoder_FreeOutputData(codec, index);
142 }
143 
AVCodecE2EDemoAPI10(const char * file)144 AVCodecE2EDemoAPI10::AVCodecE2EDemoAPI10(const char *file)
145 {
146     fd = open(file, O_RDONLY);
147     outFd = open("./output.mp4", O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
148     int64_t size = GetFileSize(file);
149     inSource = OH_AVSource_CreateWithFD(fd, 0, size);
150     if (!inSource) {
151         cout << "create source failed" << endl;
152     }
153     demuxer = OH_AVDemuxer_CreateWithSource(inSource);
154     muxer = OH_AVMuxer_Create(outFd, AV_OUTPUT_FORMAT_MPEG_4);
155     if (!muxer || !demuxer) {
156         cout << "create muxer demuxer failed" << endl;
157     }
158     dec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
159     enc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
160     if (!enc || !dec) {
161         cout << "create codec failed" << endl;
162     }
163     OH_AVFormat *sourceFormat = OH_AVSource_GetSourceFormat(inSource);
164     OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount);
165     for (int32_t index = 0; index < trackCount; index++) {
166         OH_AVDemuxer_SelectTrackByID(demuxer, index);
167         OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(inSource, index);
168         int32_t muxTrack = 0;
169         OH_AVMuxer_AddTrack(muxer, &muxTrack, trackFormat);
170         int32_t trackType = 0;
171         OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType);
172         if (trackType == MEDIA_TYPE_VID) {
173             int32_t rotation = 0;
174             double frameRate = 0.0;
175             OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_ROTATION, &rotation);
176             OH_AVFormat_GetDoubleValue(trackFormat, OH_MD_KEY_FRAME_RATE, &frameRate);
177             if (frameRate <= 0) {
178                 frameRate = DEFAULT_FRAME_RATE;
179             }
180             frameDuration = MICRO_IN_SECOND / frameRate;
181             OH_AVMuxer_SetRotation(muxer, rotation);
182             videoTrackID = index;
183             OH_AVFormat_SetIntValue(trackFormat, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
184             OH_VideoDecoder_Configure(dec, trackFormat);
185             OH_VideoEncoder_Configure(enc, trackFormat);
186         } else {
187             audioTrackID = index;
188         }
189         OH_AVFormat_Destroy(trackFormat);
190     }
191     OH_AVFormat_Destroy(sourceFormat);
192 }
193 
~AVCodecE2EDemoAPI10()194 AVCodecE2EDemoAPI10::~AVCodecE2EDemoAPI10()
195 {
196     if (dec) {
197         OH_VideoDecoder_Destroy(dec);
198     }
199     if (enc) {
200         OH_VideoEncoder_Destroy(enc);
201     }
202     if (muxer) {
203         OH_AVMuxer_Destroy(muxer);
204     }
205     if (demuxer) {
206         OH_AVDemuxer_Destroy(demuxer);
207     }
208     if (inSource) {
209         OH_AVSource_Destroy(inSource);
210     }
211     close(fd);
212     close(outFd);
213 }
214 
Configure()215 void AVCodecE2EDemoAPI10::Configure()
216 {
217     OH_AVCodecAsyncCallback encCallback;
218     encCallback.onError = OnError;
219     encCallback.onStreamChanged = OnEncStreamChanged;
220     encCallback.onNeedInputData = OnEncInputDataAvailable;
221     encCallback.onNeedOutputData = OnEncOutputDataAvailable;
222     OH_VideoEncoder_SetCallback(enc, encCallback, this);
223 
224     OH_AVCodecAsyncCallback decCallback;
225     decCallback.onError = OnError;
226     decCallback.onStreamChanged = OnDecStreamChanged;
227     decCallback.onNeedInputData = OnDecInputDataAvailable;
228     decCallback.onNeedOutputData = OnDecOutputDataAvailable;
229     OH_VideoDecoder_SetCallback(dec, decCallback, this);
230     OHNativeWindow *window = nullptr;
231     OH_VideoEncoder_GetSurface(enc, &window);
232     OH_VideoDecoder_SetSurface(dec, window);
233     isFinish.store(false);
234 }
235 
WriteAudioTrack()236 void AVCodecE2EDemoAPI10::WriteAudioTrack()
237 {
238     OH_AVMemory *buffer = nullptr;
239     buffer = OH_AVMemory_Create(AUDIO_BUFFER_SIZE);
240     while (true) {
241         if (isFinish.load()) {
242             break;
243         }
244         OH_AVCodecBufferAttr info;
245         OH_AVDemuxer_ReadSample(demuxer, audioTrackID, buffer, &info);
246         if (info.flags & AVCODEC_BUFFER_FLAGS_EOS) {
247             break;
248         }
249         OH_AVMuxer_WriteSample(muxer, audioTrackID, buffer, info);
250     }
251     OH_AVMemory_Destroy(buffer);
252 }
253 
Start()254 void AVCodecE2EDemoAPI10::Start()
255 {
256     OH_VideoDecoder_Prepare(dec);
257     OH_VideoEncoder_Prepare(enc);
258     OH_AVMuxer_Start(muxer);
259     OH_VideoEncoder_Start(enc);
260     OH_VideoDecoder_Start(dec);
261     if (audioTrackID != -1) {
262         audioThread = make_unique<thread>(&AVCodecE2EDemoAPI10::WriteAudioTrack, this);
263     }
264 }
265 
WaitForEOS()266 void AVCodecE2EDemoAPI10::WaitForEOS()
267 {
268     std::mutex waitMtx;
269     unique_lock<mutex> lock(waitMtx);
270     waitCond.wait(lock, [this]() {
271         return isFinish.load();
272     });
273     if (audioThread) {
274         audioThread->join();
275     }
276     cout << "task finish" << endl;
277 }
278 
Stop()279 void AVCodecE2EDemoAPI10::Stop()
280 {
281     OH_VideoDecoder_Stop(dec);
282     OH_VideoEncoder_Stop(enc);
283     OH_AVMuxer_Stop(muxer);
284 }