1 /*
2 * Copyright (C) 2023 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 "avmuxer_demo_base.h"
16 #include <unistd.h>
17 #include <iostream>
18 #include <fstream>
19 #include "avcodec_errors.h"
20 #include "avcodec_common.h"
21
22 namespace {
23 constexpr int MODE_ZERO = 0;
24 constexpr int MODE_ONE = 1;
25 constexpr int MODE_TWO = 2;
26 constexpr int MODE_THREE = 3;
27 constexpr int CONFIG_BUFFER_SZIE = 0x1FFF;
28 }
29
30 namespace OHOS {
31 namespace MediaAVCodec {
32 const AudioTrackParam *AVMuxerDemoBase::audioParams_ = nullptr;
33 const VideoTrackParam *AVMuxerDemoBase::videoParams_ = nullptr;
34 const VideoTrackParam *AVMuxerDemoBase::coverParams_ = nullptr;
35 std::string AVMuxerDemoBase::videoType_ = std::string("");
36 std::string AVMuxerDemoBase::audioType_ = std::string("");
37 std::string AVMuxerDemoBase::coverType_ = std::string("");
38 std::string AVMuxerDemoBase::format_ = std::string("");
39 OutputFormat AVMuxerDemoBase::outputFormat_ = OUTPUT_FORMAT_DEFAULT;
40 bool AVMuxerDemoBase::hasSetMode_ = false;
41
AVMuxerDemoBase()42 AVMuxerDemoBase::AVMuxerDemoBase()
43 {
44 }
45
OpenFile(const std::string & filePath)46 std::shared_ptr<std::ifstream> OpenFile(const std::string &filePath)
47 {
48 auto file = std::make_shared<std::ifstream>();
49 file->open(filePath, std::ios::in | std::ios::binary);
50 if (file->is_open()) {
51 return file;
52 }
53
54 return nullptr;
55 }
56
SelectFormatMode()57 void AVMuxerDemoBase::SelectFormatMode()
58 {
59 int num;
60 std::cout<<"\nplease select muxer type: 0.mp4 1.m4a"<<std::endl;
61 std::cin>>num;
62 switch (num) {
63 case MODE_ZERO:
64 format_ = "mp4";
65 outputFormat_ = OUTPUT_FORMAT_MPEG_4;
66 break;
67 case MODE_ONE:
68 format_ = "m4a";
69 outputFormat_ = OUTPUT_FORMAT_M4A;
70 break;
71 default:
72 format_ = "mp4";
73 outputFormat_ = OUTPUT_FORMAT_MPEG_4;
74 break;
75 }
76 }
77
SelectAudioVideoMode()78 void AVMuxerDemoBase::SelectAudioVideoMode()
79 {
80 int num;
81 std::cout<<"\nplease select audio file: 0.noAudio 1.aac 2.mpeg"<<std::endl;
82 std::cin>>num;
83 switch (num) {
84 case MODE_ZERO:
85 audioType_ = "noAudio";
86 audioParams_ = nullptr;
87 break;
88 case MODE_ONE:
89 audioType_ = "aac";
90 audioParams_ = &g_audioAacPar;
91 break;
92 case MODE_TWO:
93 audioType_ = "mpeg";
94 audioParams_ = &g_audioMpegPar;
95 break;
96 default:
97 videoType_ = "noAudio";
98 audioParams_ = nullptr;
99 std::cout<<"do not support audio type index: "<<num<<", set to noAudio"<<std::endl;
100 break;
101 }
102
103 std::cout<<"please select video file:0.noVideo 1.h264 2.mpeg4 3.h265"<<std::endl;
104 std::cin>>num;
105 switch (num) {
106 case MODE_ZERO:
107 videoType_ = "noVideo";
108 videoParams_ = nullptr;
109 break;
110 case MODE_ONE:
111 videoType_ = "h264";
112 videoParams_ = &g_videoH264Par;
113 break;
114 case MODE_TWO:
115 videoType_ = "mpeg4";
116 videoParams_ = &g_videoMpeg4Par;
117 break;
118 case MODE_THREE:
119 videoType_ = "h265";
120 videoParams_ = &g_videoH265Par;
121 break;
122 default:
123 videoType_ = "noVideo";
124 videoParams_ = nullptr;
125 std::cout<<"do not support video type index: "<<", set to noVideo"<<num<<std::endl;
126 break;
127 }
128 }
129
SelectCoverMode()130 void AVMuxerDemoBase::SelectCoverMode()
131 {
132 int num;
133 std::cout<<"please select cover file:0.NoCover 1.jpg 2.png 3.bmp"<<std::endl;
134 std::cin>>num;
135 switch (num) {
136 case MODE_ZERO:
137 coverType_ = "noCover";
138 coverParams_ = nullptr;
139 break;
140 case MODE_ONE:
141 coverType_ = "jpg";
142 coverParams_ = &g_jpegCoverPar;
143 break;
144 case MODE_TWO:
145 coverType_ = "png";
146 coverParams_ = &g_pngCoverPar;
147 break;
148 case MODE_THREE:
149 coverType_ = "bmp";
150 coverParams_ = &g_bmpCoverPar;
151 break;
152 default:
153 coverType_ = "noCover";
154 coverParams_ = nullptr;
155 std::cout<<"do not support cover type index: "<<", set to noCover"<<num<<std::endl;
156 break;
157 }
158 }
159
SelectMode()160 int AVMuxerDemoBase::SelectMode()
161 {
162 if (hasSetMode_) {
163 return 0;
164 }
165 SelectFormatMode();
166 SelectAudioVideoMode();
167 SelectCoverMode();
168
169 hasSetMode_ = true;
170 return 0;
171 }
172
SelectModeAndOpenFile()173 int AVMuxerDemoBase::SelectModeAndOpenFile()
174 {
175 if (SelectMode() != 0) {
176 return -1;
177 }
178
179 if (audioParams_ != nullptr) {
180 audioFile_ = OpenFile(audioParams_->fileName);
181 if (audioFile_ == nullptr) {
182 std::cout<<"open audio file failed! file name:"<<audioParams_->fileName<<std::endl;
183 return -1;
184 }
185 std::cout<<"open audio file success! file name:"<<audioParams_->fileName<<std::endl;
186 }
187
188 if (videoParams_ != nullptr) {
189 videoFile_ = OpenFile(videoParams_->fileName);
190 if (videoFile_ == nullptr) {
191 std::cout<<"open video file failed! file name:"<<videoParams_->fileName<<std::endl;
192 Reset();
193 return -1;
194 }
195 std::cout<<"video file success! file name:"<<videoParams_->fileName<<std::endl;
196 }
197
198 if (coverParams_ != nullptr) {
199 coverFile_ = OpenFile(coverParams_->fileName);
200 if (coverFile_ == nullptr) {
201 std::cout<<"open cover file failed! file name:"<<coverParams_->fileName<<std::endl;
202 Reset();
203 return -1;
204 }
205 std::cout<<"cover file success! file name:"<<coverParams_->fileName<<std::endl;
206 }
207 return 0;
208 }
209
Reset()210 void AVMuxerDemoBase::Reset()
211 {
212 if (outFd_ > 0) {
213 close(outFd_);
214 outFd_ = -1;
215 }
216 if (audioFile_ != nullptr) {
217 audioFile_->close();
218 audioFile_ = nullptr;
219 }
220 if (videoFile_ != nullptr) {
221 videoFile_->close();
222 videoFile_ = nullptr;
223 }
224 if (coverFile_ != nullptr) {
225 coverFile_->close();
226 coverFile_ = nullptr;
227 }
228 }
229
RunCase()230 void AVMuxerDemoBase::RunCase()
231 {
232 if (SelectModeAndOpenFile() != 0) {
233 return;
234 }
235
236 DoRunMuxer();
237
238 Reset();
239 }
240
RunMultiThreadCase()241 void AVMuxerDemoBase::RunMultiThreadCase()
242 {
243 std::cout<<"==== start AVMuxerDemoBase::RunMultiThreadCase ==="<<std::endl;
244 if (SelectModeAndOpenFile() != 0) {
245 return;
246 }
247
248 DoRunMultiThreadCase();
249
250 Reset();
251 }
252
WriteSingleTrackSample(uint32_t trackId,std::shared_ptr<std::ifstream> file)253 void AVMuxerDemoBase::WriteSingleTrackSample(uint32_t trackId, std::shared_ptr<std::ifstream> file)
254 {
255 if (file == nullptr) {
256 std::cout<<"AVMuxerDemoBase::WriteTrackSample file is nullptr"<<std::endl;
257 return;
258 }
259 std::shared_ptr<AVSharedMemoryBase> buffer = nullptr;
260 AVCodecBufferInfo info {0, 0, 0};
261 AVCodecBufferFlag flag = AVCODEC_BUFFER_FLAG_NONE;
262 bool ret = ReadSampleDataInfo(file, buffer, info, flag);
263 while (ret) {
264 if (DoWriteSample(trackId, buffer, info, flag) != AVCS_ERR_OK) {
265 std::cout<<"WriteSample failed"<<std::endl;
266 break;
267 }
268 ret = ReadSampleDataInfo(file, buffer, info, flag);
269 }
270 }
271
ReadSampleDataInfo(std::shared_ptr<std::ifstream> file,std::shared_ptr<AVSharedMemoryBase> & buffer,AVCodecBufferInfo & info,AVCodecBufferFlag & flag)272 bool AVMuxerDemoBase::ReadSampleDataInfo(std::shared_ptr<std::ifstream> file,
273 std::shared_ptr<AVSharedMemoryBase> &buffer,
274 AVCodecBufferInfo &info,
275 AVCodecBufferFlag &flag)
276 {
277 if (file->eof()) {
278 return false;
279 }
280 file->read(reinterpret_cast<char*>(&info.presentationTimeUs), sizeof(info.presentationTimeUs));
281
282 if (file->eof()) {
283 return false;
284 }
285 file->read(reinterpret_cast<char*>(&flag), sizeof(flag));
286 if (flag & 0x01) {
287 flag = AVCODEC_BUFFER_FLAG_SYNC_FRAME;
288 }
289
290 if (file->eof()) {
291 return false;
292 }
293 file->read(reinterpret_cast<char*>(&info.size), sizeof(info.size));
294
295 if (file->eof()) {
296 return false;
297 }
298 if (buffer == nullptr || buffer->GetSize() < info.size) {
299 buffer = std::make_shared<AVSharedMemoryBase>(info.size, AVSharedMemory::FLAGS_READ_ONLY, "sampleData");
300 buffer->Init();
301 }
302 file->read(reinterpret_cast<char*>(buffer->GetBase()), info.size);
303 return true;
304 }
305
WriteAvTrackSample()306 void AVMuxerDemoBase::WriteAvTrackSample()
307 {
308 if (audioFile_ == nullptr || videoFile_ == nullptr) {
309 return;
310 }
311 AVCodecBufferInfo audioInfo {0, 0, 0};
312 AVCodecBufferInfo videoInfo {0, 0, 0};
313 AVCodecBufferFlag audioFlag = AVCODEC_BUFFER_FLAG_NONE;
314 AVCodecBufferFlag videoFlag = AVCODEC_BUFFER_FLAG_NONE;
315 std::shared_ptr<AVSharedMemoryBase> audioBuffer = nullptr;
316 std::shared_ptr<AVSharedMemoryBase> videoBuffer = nullptr;
317 bool audioRet = ReadSampleDataInfo(audioFile_, audioBuffer, audioInfo, audioFlag);
318 bool videoRet = ReadSampleDataInfo(videoFile_, videoBuffer, videoInfo, videoFlag);
319 bool isOver = false;
320 while (!isOver && (audioRet || videoRet)) {
321 int ret = AVCS_ERR_OK;
322 if (audioRet && videoRet && audioInfo.presentationTimeUs <= videoInfo.presentationTimeUs) {
323 ret = DoWriteSample(audioTrackId_, audioBuffer, audioInfo, audioFlag);
324 audioRet = ReadSampleDataInfo(audioFile_, audioBuffer, audioInfo, audioFlag);
325 } else if (audioRet && videoRet) {
326 ret = DoWriteSample(videoTrackId_, videoBuffer, videoInfo, videoFlag);
327 videoRet = ReadSampleDataInfo(videoFile_, videoBuffer, videoInfo, videoFlag);
328 } else if (audioRet) {
329 ret = DoWriteSample(audioTrackId_, audioBuffer, audioInfo, audioFlag);
330 isOver = true;
331 } else {
332 ret = DoWriteSample(videoTrackId_, videoBuffer, videoInfo, videoFlag);
333 isOver = true;
334 }
335 if (ret != AVCS_ERR_OK) {
336 std::cout<<"WriteSample failed"<<std::endl;
337 break;
338 }
339 }
340 }
341
WriteTrackSample()342 void AVMuxerDemoBase::WriteTrackSample()
343 {
344 if (audioFile_ != nullptr && videoFile_ != nullptr && audioTrackId_ >= 0 && videoTrackId_ >= 0) {
345 std::cout<<"AVMuxerDemoBase::WriteTrackSample write AUDIO and VIDEO sample"<<std::endl;
346 std::cout<<"audio trackId:"<<audioTrackId_<<" video trackId:"<<videoTrackId_<<std::endl;
347 WriteAvTrackSample();
348 } else if (audioFile_ != nullptr && audioTrackId_ >= 0) {
349 std::cout<<"AVMuxerDemoBase::WriteTrackSample write AUDIO sample"<<std::endl;
350 WriteSingleTrackSample(audioTrackId_, audioFile_);
351 } else if (videoFile_ != nullptr && videoTrackId_ >= 0) {
352 std::cout<<"AVMuxerDemoBase::WriteTrackSample write VIDEO sample"<<std::endl;
353 WriteSingleTrackSample(videoTrackId_, videoFile_);
354 } else {
355 std::cout<<"AVMuxerDemoBase::WriteTrackSample don't write AUDIO and VIDEO track!!"<<std::endl;
356 }
357 }
358
MulThdWriteTrackSample(AVMuxerDemoBase * muxerBase,uint32_t trackId,std::shared_ptr<std::ifstream> file)359 void AVMuxerDemoBase::MulThdWriteTrackSample(AVMuxerDemoBase *muxerBase, uint32_t trackId,
360 std::shared_ptr<std::ifstream> file)
361 {
362 muxerBase->WriteSingleTrackSample(trackId, file);
363 }
364
WriteCoverSample()365 void AVMuxerDemoBase::WriteCoverSample()
366 {
367 if (coverParams_ == nullptr) {
368 return;
369 }
370 std::cout<<"AVMuxerDemoBase::WriteCoverSample"<<std::endl;
371 if (coverFile_ == nullptr) {
372 std::cout<<"AVMuxerDemoBase::WriteCoverSample coverFile_ is nullptr!"<<std::endl;
373 return;
374 }
375 AVCodecBufferInfo info {0, 0, 0};
376 coverFile_->seekg(0, std::ios::end);
377 info.size = coverFile_->tellg();
378 coverFile_->seekg(0, std::ios::beg);
379 if (info.size <= 0) {
380 std::cout<<"AVMuxerDemoBase::WriteCoverSample coverFile_ size is 0!"<<std::endl;
381 return;
382 }
383
384 std::shared_ptr<AVSharedMemoryBase> avMemBuffer =
385 std::make_shared<AVSharedMemoryBase>(info.size, AVSharedMemory::FLAGS_READ_ONLY, "sampleData");
386 avMemBuffer->Init();
387 coverFile_->read(reinterpret_cast<char*>(avMemBuffer->GetBase()), info.size);
388 if (DoWriteSample(coverTrackId_, avMemBuffer, info, AVCODEC_BUFFER_FLAG_NONE) != AVCS_ERR_OK) {
389 std::cout<<"WriteCoverSample error"<<std::endl;
390 }
391 }
392
AddVideoTrack(const VideoTrackParam * param)393 int AVMuxerDemoBase::AddVideoTrack(const VideoTrackParam *param)
394 {
395 if (param == nullptr) {
396 std::cout<<"AVMuxerDemoBase::AddVideoTrack video is not select!"<<std::endl;
397 return -1;
398 }
399 MediaDescription videoParams;
400 videoParams.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, param->mimeType);
401 videoParams.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, param->width);
402 videoParams.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, param->height);
403 videoParams.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, param->frameRate);
404 videoParams.PutIntValue(MediaDescriptionKey::MD_KEY_VIDEO_DELAY, param->videoDelay);
405
406 int extSize = 0;
407 char buffer[CONFIG_BUFFER_SZIE] {0};
408 videoFile_->read(reinterpret_cast<char*>(&extSize), sizeof(extSize));
409 if (extSize > 0 && extSize < CONFIG_BUFFER_SZIE) {
410 videoFile_->read(reinterpret_cast<char*>(buffer), extSize);
411 videoParams.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, reinterpret_cast<uint8_t*>(buffer), extSize);
412 } else {
413 std::cout<<"AVMuxerDemoBase::AddVideoTrack DoAddTrack failed!"<<std::endl;
414 }
415
416 if (DoAddTrack(videoTrackId_, videoParams) != AVCS_ERR_OK) {
417 return -1;
418 }
419 std::cout << "AVMuxerDemoBase::AddVideoTrack video trackId is: " << videoTrackId_ << std::endl;
420 return 0;
421 }
422
AddAudioTrack(const AudioTrackParam * param)423 int AVMuxerDemoBase::AddAudioTrack(const AudioTrackParam *param)
424 {
425 if (param == nullptr) {
426 std::cout<<"AVMuxerDemoBase::AddAudioTrack audio is not select!"<<std::endl;
427 return -1;
428 }
429 MediaDescription audioParams;
430 audioParams.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, param->mimeType);
431 audioParams.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, param->sampleRate);
432 audioParams.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, param->channels);
433 audioParams.PutIntValue(MediaDescriptionKey::MD_KEY_AUDIO_SAMPLES_PER_FRAME, param->frameSize);
434
435 int extSize = 0;
436 char buffer[CONFIG_BUFFER_SZIE] {0};
437 audioFile_->read(reinterpret_cast<char*>(&extSize), sizeof(extSize));
438 if (extSize > 0 && extSize < CONFIG_BUFFER_SZIE) {
439 audioFile_->read(reinterpret_cast<char*>(buffer), extSize);
440 audioParams.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, reinterpret_cast<uint8_t*>(buffer), extSize);
441 } else {
442 std::cout<<"AVMuxerDemoBase::AddAudioTrack error extSize:"<<extSize<<std::endl;
443 }
444
445 if (DoAddTrack(audioTrackId_, audioParams) != 0) {
446 std::cout<<"AVMuxerDemoBase::AddAudioTrack DoAddTrack failed!"<<std::endl;
447 return -1;
448 }
449 std::cout << "AVMuxerDemoBase::AddAudioTrack audio trackId is: " << audioTrackId_ << std::endl;
450 return 0;
451 }
452
AddCoverTrack(const VideoTrackParam * param)453 int AVMuxerDemoBase::AddCoverTrack(const VideoTrackParam *param)
454 {
455 if (param == nullptr) {
456 std::cout<<"AVMuxerDemoBase::AddCoverTrack cover is not select!"<<std::endl;
457 return -1;
458 }
459 MediaDescription coverParams;
460 coverParams.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, param->mimeType);
461 coverParams.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, param->width);
462 coverParams.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, param->height);
463
464 if (DoAddTrack(coverTrackId_, coverParams) != AVCS_ERR_OK) {
465 return -1;
466 }
467 std::cout << "AVMuxerDemoBase::AddCoverTrack video trackId is: " << coverTrackId_ << std::endl;
468 return 0;
469 }
470 } // MediaAVCodec
471 } // OHOS