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 }