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.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 double DEFAULT_FRAME_RATE = 25.0;
39 FILE *demuxerOutFp = nullptr;
40
GetFileSize(const char * fileName)41 static int64_t GetFileSize(const char *fileName)
42 {
43 int64_t fileSize = 0;
44 if (fileName != nullptr) {
45 struct stat fileStatus {};
46 if (stat(fileName, &fileStatus) == 0) {
47 fileSize = static_cast<int64_t>(fileStatus.st_size);
48 }
49 }
50 return fileSize;
51 }
52
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)53 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
54 {
55 (void)codec;
56 (void)userData;
57 cout<<"error :"<<errorCode<<endl;
58 }
59
OnDecStreamChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)60 static void OnDecStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
61 {
62 (void)codec;
63 (void)format;
64 (void)userData;
65 }
66
OnDecInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)67 static void OnDecInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
68 {
69 AVCodecE2EDemo *demo = static_cast<AVCodecE2EDemo*>(userData);
70 OH_AVDemuxer_ReadSampleBuffer(demo->demuxer, demo->videoTrackID, buffer);
71 uint8_t *data = OH_AVBuffer_GetAddr(buffer);
72 OH_AVCodecBufferAttr attr;
73 OH_AVBuffer_GetBufferAttr(buffer, &attr);
74 if (attr.size > 0) {
75 fwrite(data, attr.size, 1, demuxerOutFp);
76 }
77
78 OH_VideoDecoder_PushInputBuffer(codec, index);
79 }
80
OnDecOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)81 static void OnDecOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
82 {
83 AVCodecE2EDemo *demo = static_cast<AVCodecE2EDemo*>(userData);
84 OH_AVCodecBufferAttr attr;
85 OH_AVBuffer_GetBufferAttr(buffer, &attr);
86 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
87 OH_VideoEncoder_NotifyEndOfStream(demo->enc);
88 return;
89 }
90 OH_VideoDecoder_RenderOutputBuffer(codec, index);
91 }
92
OnEncStreamChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)93 static void OnEncStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
94 {
95 cout<<"format changed"<<endl;
96 }
97
OnEncInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)98 static void OnEncInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
99 {
100 (void)codec;
101 (void)index;
102 (void)buffer;
103 (void)userData;
104 }
105
OnEncOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)106 static void OnEncOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
107 {
108 AVCodecE2EDemo *demo = static_cast<AVCodecE2EDemo*>(userData);
109 OH_AVCodecBufferAttr attr;
110 OH_AVBuffer_GetBufferAttr(buffer, &attr);
111 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
112 demo->isFinish.store(true);
113 demo->waitCond.notify_all();
114 return;
115 }
116 OH_AVMuxer_WriteSampleBuffer(demo->muxer, demo->videoTrackID, buffer);
117 OH_VideoEncoder_FreeOutputBuffer(codec, index);
118 }
119
AVCodecE2EDemo(const char * file)120 AVCodecE2EDemo::AVCodecE2EDemo(const char *file)
121 {
122 fd = open(file, O_RDONLY);
123 demuxerOutFp = fopen("out.h265", "wb");
124 outFd = open("./output.mp4", O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
125 int64_t size = GetFileSize(file);
126 inSource = OH_AVSource_CreateWithFD(fd, 0, size);
127 if (!inSource) {
128 cout << "create source failed" << endl;
129 }
130 demuxer = OH_AVDemuxer_CreateWithSource(inSource);
131 muxer = OH_AVMuxer_Create(outFd, AV_OUTPUT_FORMAT_MPEG_4);
132 if (!muxer || !demuxer) {
133 cout << "create muxer demuxer failed" << endl;
134 }
135 dec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
136 enc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
137 if (!enc || !dec) {
138 cout << "create codec failed" << endl;
139 }
140 OH_AVFormat *sourceFormat = OH_AVSource_GetSourceFormat(inSource);
141 OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount);
142 for (int32_t index = 0; index < trackCount; index++) {
143 OH_AVDemuxer_SelectTrackByID(demuxer, index);
144 OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(inSource, index);
145 OH_AVFormat *trackFormatEnc = OH_AVSource_GetTrackFormat(inSource, index);
146 int32_t muxTrack = 0;
147
148 int32_t trackType = -1;
149 OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType);
150 if (trackType == MEDIA_TYPE_VID) {
151 int32_t rotation = 0;
152 double frameRate = 0.0;
153 OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_ROTATION, &rotation);
154 OH_AVFormat_GetDoubleValue(trackFormat, OH_MD_KEY_FRAME_RATE, &frameRate);
155 if (frameRate <= 0) {
156 frameRate = DEFAULT_FRAME_RATE;
157 }
158 frameDuration = MICRO_IN_SECOND / frameRate;
159 OH_AVMuxer_SetRotation(muxer, rotation);
160 videoTrackID = index;
161 OH_AVFormat_SetIntValue(trackFormat, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
162 OH_VideoDecoder_Configure(dec, trackFormat);
163 OH_VideoEncoder_Configure(enc, trackFormatEnc);
164 } else if (trackType == MEDIA_TYPE_AUD) {
165 audioTrackID = index;
166 }
167 OH_AVMuxer_AddTrack(muxer, &muxTrack, trackFormatEnc);
168 OH_AVFormat_Destroy(trackFormat);
169 }
170 OH_AVFormat_Destroy(sourceFormat);
171 }
172
~AVCodecE2EDemo()173 AVCodecE2EDemo::~AVCodecE2EDemo()
174 {
175 if (dec) {
176 OH_VideoDecoder_Destroy(dec);
177 }
178 if (enc) {
179 OH_VideoEncoder_Destroy(enc);
180 }
181 if (muxer) {
182 OH_AVMuxer_Destroy(muxer);
183 }
184 if (demuxer) {
185 OH_AVDemuxer_Destroy(demuxer);
186 }
187 if (inSource) {
188 OH_AVSource_Destroy(inSource);
189 }
190 close(fd);
191 close(outFd);
192 fclose(demuxerOutFp);
193 }
194
Configure()195 void AVCodecE2EDemo::Configure()
196 {
197 OH_AVCodecCallback encCallback;
198 encCallback.onError = OnError;
199 encCallback.onStreamChanged = OnEncStreamChanged;
200 encCallback.onNeedInputBuffer = OnEncInputBufferAvailable;
201 encCallback.onNewOutputBuffer = OnEncOutputBufferAvailable;
202 OH_VideoEncoder_RegisterCallback(enc, encCallback, this);
203
204 OH_AVCodecCallback decCallback;
205 decCallback.onError = OnError;
206 decCallback.onStreamChanged = OnDecStreamChanged;
207 decCallback.onNeedInputBuffer = OnDecInputBufferAvailable;
208 decCallback.onNewOutputBuffer = OnDecOutputBufferAvailable;
209 OH_VideoDecoder_RegisterCallback(dec, decCallback, this);
210 OHNativeWindow *window = nullptr;
211 OH_VideoEncoder_GetSurface(enc, &window);
212 OH_VideoDecoder_SetSurface(dec, window);
213 isFinish.store(false);
214 }
215
WriteAudioTrack()216 void AVCodecE2EDemo::WriteAudioTrack()
217 {
218 OH_AVBuffer *buffer = nullptr;
219 buffer = OH_AVBuffer_Create(AUDIO_BUFFER_SIZE);
220 while (true) {
221 if (isFinish.load()) {
222 break;
223 }
224 OH_AVDemuxer_ReadSampleBuffer(demuxer, audioTrackID, buffer);
225 OH_AVCodecBufferAttr attr;
226 OH_AVBuffer_GetBufferAttr(buffer, &attr);
227 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
228 break;
229 }
230 OH_AVMuxer_WriteSampleBuffer(muxer, audioTrackID, buffer);
231 }
232 OH_AVBuffer_Destroy(buffer);
233 }
234
Start()235 void AVCodecE2EDemo::Start()
236 {
237 OH_VideoDecoder_Prepare(dec);
238 OH_VideoEncoder_Prepare(enc);
239 OH_AVMuxer_Start(muxer);
240 OH_VideoEncoder_Start(enc);
241 OH_VideoDecoder_Start(dec);
242 cout<<"e2e demo start" <<endl;
243 if (audioTrackID != -1) {
244 audioThread = make_unique<thread>(&AVCodecE2EDemo::WriteAudioTrack, this);
245 }
246 }
247
WaitForEOS()248 void AVCodecE2EDemo::WaitForEOS()
249 {
250 std::mutex waitMtx;
251 unique_lock<mutex> lock(waitMtx);
252 waitCond.wait(lock, [this]() {
253 return isFinish.load();
254 });
255 if (audioThread) {
256 audioThread->join();
257 }
258 cout << "task finish" << endl;
259 }
260
Stop()261 void AVCodecE2EDemo::Stop()
262 {
263 OH_VideoDecoder_Stop(dec);
264 OH_VideoEncoder_Stop(enc);
265 OH_AVMuxer_Stop(muxer);
266 }