• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "hdrmuxer_sample.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 "media_description.h"
27 
28 using namespace OHOS;
29 using namespace OHOS::MediaAVCodec;
30 using namespace std;
31 constexpr int64_t MICRO_IN_SECOND = 1000000L;
32 constexpr int32_t AUDIO_BUFFER_SIZE = 1024 * 1024;
33 constexpr double DEFAULT_FRAME_RATE = 25.0;
34 constexpr uint32_t INVALID_TRACK_ID = -1;
35 
GetFileSize(const char * fileName)36 static int64_t GetFileSize(const char *fileName)
37 {
38     int64_t fileSize = 0;
39     if (fileName != nullptr) {
40         struct stat fileStatus {};
41         if (stat(fileName, &fileStatus) == 0) {
42             fileSize = static_cast<int64_t>(fileStatus.st_size);
43         }
44     }
45     return fileSize;
46 }
47 
48 
InitMuxerDeMuxer(const char * mp4File)49 bool MuxerSample::InitMuxerDeMuxer(const char *mp4File)
50 {
51     fd = open(mp4File, O_RDONLY);
52     outFd = open("./output.mp4", O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
53     int64_t size = GetFileSize(mp4File);
54     inSource = OH_AVSource_CreateWithFD(fd, 0, size);
55     if (!inSource) {
56         cout << "create source failed" << endl;
57         return false;
58     }
59 
60     demuxer = OH_AVDemuxer_CreateWithSource(inSource);
61     muxer = OH_AVMuxer_Create(outFd, AV_OUTPUT_FORMAT_MPEG_4);
62     if (!muxer || !demuxer) {
63         cout << "create muxer demuxer failed" << endl;
64         return false;
65     }
66 
67     OH_AVFormat *sourceFormat = OH_AVSource_GetSourceFormat(inSource);
68     OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount);
69 
70     for (int32_t index = 0; index < trackCount; index++) {
71         OH_AVDemuxer_SelectTrackByID(demuxer, index);
72         OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(inSource, index);
73         int32_t muxTrack = 0;
74         int32_t trackType = -1;
75         OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType);
76         if (trackType == MEDIA_TYPE_VID) {
77             double frameRate = 0.0;
78             OH_AVFormat_GetDoubleValue(trackFormat, OH_MD_KEY_FRAME_RATE, &frameRate);
79             if (frameRate <= 0) {
80                 frameRate = DEFAULT_FRAME_RATE;
81             }
82             if (frameRate != 0) {
83                 frameDuration = MICRO_IN_SECOND / frameRate;
84             }
85             videoTrackID = index;
86             OH_AVFormat_SetIntValue(trackFormat, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
87         } else if (trackType == MEDIA_TYPE_AUD) {
88             audioTrackID = index;
89         }
90         OH_AVMuxer_AddTrack(muxer, &muxTrack, trackFormat);
91         OH_AVFormat_Destroy(trackFormat);
92     }
93     OH_AVFormat_Destroy(sourceFormat);
94     return true;
95 }
96 
~MuxerSample()97 MuxerSample::~MuxerSample()
98 {
99     if (muxer) {
100         OH_AVMuxer_Destroy(muxer);
101     }
102     if (demuxer) {
103         OH_AVDemuxer_Destroy(demuxer);
104     }
105     if (inSource) {
106         OH_AVSource_Destroy(inSource);
107     }
108     close(fd);
109     close(outFd);
110 }
111 
RunHdrMuxer(const uint8_t * data,size_t size,const char * mp4File)112 void MuxerSample::RunHdrMuxer(const uint8_t *data, size_t size, const char *mp4File)
113 {
114     fuzzSize = size;
115     fuzzData = data;
116     bool ret = InitMuxerDeMuxer(mp4File);
117     if (!ret) {
118         cout << "InitMuxerDeMuxer failed" << endl;
119         return;
120     }
121     Start();
122     WaitForEOS();
123 }
124 
WriteAudioTrack()125 void MuxerSample::WriteAudioTrack()
126 {
127     OH_AVBuffer *buffer = nullptr;
128     buffer = OH_AVBuffer_Create(AUDIO_BUFFER_SIZE);
129     while (!isAudioFinish.load()) {
130         OH_AVDemuxer_ReadSampleBuffer(demuxer, audioTrackID, buffer);
131         OH_AVCodecBufferAttr attr;
132         OH_AVBuffer_GetBufferAttr(buffer, &attr);
133         if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
134             break;
135         }
136         OH_AVMuxer_WriteSampleBuffer(muxer, audioTrackID, buffer);
137         isAudioFinish.store(true);
138         waitCond.notify_all();
139     }
140     OH_AVBuffer_Destroy(buffer);
141 }
142 
WriteVideoTrack()143 void MuxerSample::WriteVideoTrack()
144 {
145     OH_AVBuffer *buffer = nullptr;
146     buffer = OH_AVBuffer_Create(fuzzSize);
147     while (!isVideoFinish.load()) {
148         uint8_t *bufferAddr = OH_AVBuffer_GetAddr(buffer);
149         if (bufferAddr == nullptr) {
150             return;
151         }
152         memcpy_s(bufferAddr, fuzzSize, fuzzData, fuzzSize);
153         OH_AVCodecBufferAttr attr;
154         OH_AVBuffer_GetBufferAttr(buffer, &attr);
155         if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
156             break;
157         }
158         OH_AVMuxer_WriteSampleBuffer(muxer, videoTrackID, buffer);
159         isVideoFinish.store(true);
160         waitCond.notify_all();
161     }
162     OH_AVBuffer_Destroy(buffer);
163 }
164 
Start()165 void MuxerSample::Start()
166 {
167     OH_AVMuxer_Start(muxer);
168     cout << "hdr muxer start" << endl;
169     if (audioTrackID != INVALID_TRACK_ID) {
170         audioThread = make_unique<thread>(&MuxerSample::WriteAudioTrack, this);
171     }
172     if (videoTrackID != INVALID_TRACK_ID) {
173         videoThread = make_unique<thread>(&MuxerSample::WriteVideoTrack, this);
174     }
175 }
176 
WaitForEOS()177 void MuxerSample::WaitForEOS()
178 {
179     std::mutex audioWaitMtx;
180     std::mutex videoWaitMtx;
181     unique_lock<mutex> audioLock(audioWaitMtx);
182     unique_lock<mutex> videoLock(videoWaitMtx);
183     if (audioThread != nullptr) {
184         waitCond.wait(audioLock, [this]() {
185             return isAudioFinish.load();
186         });
187     }
188     if (videoThread != nullptr) {
189         waitCond.wait(videoLock, [this]() {
190             return isVideoFinish.load();
191         });
192     }
193     if (audioThread != nullptr) {
194         audioThread->join();
195     }
196     if (videoThread != nullptr) {
197         videoThread->join();
198     }
199 }
200 
Stop()201 void MuxerSample::Stop()
202 {
203     OH_AVMuxer_Stop(muxer);
204 }