• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "hdrcodec_sample.h"
16 #include <iostream>
17 #include <string>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <list>
22 #include <arpa/inet.h>
23 #include <sys/time.h>
24 #include <utility>
25 #include <memory>
26 
27 #include "av_common.h"
28 
29 #include "avcodec_common.h"
30 #include "native_avdemuxer.h"
31 #include "native_avsource.h"
32 #include "native_avmuxer.h"
33 #include "avcodec_errors.h"
34 #include "native_avformat.h"
35 #include "native_avcodec_base.h"
36 #include "media_description.h"
37 #include "native_avmemory.h"
38 #include "native_averrors.h"
39 #include "surface/window.h"
40 #include "openssl/crypto.h"
41 #include "openssl/sha.h"
42 using namespace OHOS;
43 using namespace OHOS::Media;
44 using namespace std;
45 namespace {
46 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
47 constexpr int64_t NANOS_IN_MICRO = 1000L;
48 std::shared_ptr<std::ifstream> inFile_;
49 std::condition_variable g_cv;
50 std::atomic<bool> g_isRunning = true;
51 constexpr uint32_t START_CODE_SIZE = 4;
52 constexpr int32_t EIGHT = 8;
53 constexpr int32_t SIXTEEN = 16;
54 constexpr int32_t TWENTY_FOUR = 24;
55 constexpr uint8_t H264_NALU_TYPE = 0x1f;
56 constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1};
57 constexpr uint8_t SPS = 7;
58 constexpr uint8_t PPS = 8;
59 constexpr uint8_t MPEG2_FRAME_HEAD[] = {0x00, 0x00, 0x01, 0x00};
60 constexpr uint8_t MPEG2_SEQUENCE_HEAD[] = {0x00, 0x00, 0x01, 0xb3};
61 constexpr uint8_t MPEG4_FRAME_HEAD[] = {0x00, 0x00, 0x01, 0xb6};
62 constexpr uint8_t MPEG4_SEQUENCE_HEAD[] = {0x00, 0x00, 0x01, 0xb0};
63 constexpr uint32_t PREREAD_BUFFER_SIZE = 0.1 * 1024 * 1024;
64 constexpr uint32_t MAX_WIDTH = 4000;
65 constexpr uint32_t MAX_HEIGHT = 3000;
66 constexpr uint32_t MAX_NALU_SIZE = MAX_WIDTH * MAX_HEIGHT << 1;
67 constexpr int32_t AUDIO_BUFFER_SIZE = 1024 * 1024;
68 constexpr int32_t CHANNEL_0 = 0;
69 constexpr int32_t CHANNEL_1 = 1;
70 constexpr int32_t CHANNEL_2 = 2;
71 constexpr int32_t CHANNEL_3 = 3;
72 constexpr int32_t CHANNEL_4 = 4;
73 }
74 
GetSystemTimeUs()75 int64_t GetSystemTimeUs()
76 {
77     struct timespec now;
78     (void)clock_gettime(CLOCK_BOOTTIME, &now);
79     int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
80 
81     return nanoTime / NANOS_IN_MICRO;
82 }
83 
VdecFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)84 void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
85 {
86     cout << "Format Changed" << endl;
87 }
88 
VdecInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)89 void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
90 {
91     HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
92     VSignal *signal = sample->decSignal;
93     unique_lock<mutex> lock(signal->inMutex_);
94     if (sample->DEMUXER_FLAG) {
95         OH_AVCodecBufferAttr attr;
96         OH_AVDemuxer_ReadSample(sample->demuxer, sample->videoTrackID, data, &attr);
97         OH_VideoDecoder_PushInputData(codec, index, attr);
98     } else {
99         signal->inIdxQueue_.push(index);
100         signal->inBufferQueue_.push(data);
101         signal->inCond_.notify_all();
102     }
103 }
104 
VdecOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)105 void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
106                          void *userData)
107 {
108     HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
109     if (attr->flags & AVCODEC_BUFFER_FLAGS_EOS) {
110         OH_VideoEncoder_NotifyEndOfStream(sample->venc_);
111     } else {
112         OH_VideoDecoder_RenderOutputData(codec, index);
113         sample->frameCountDec++;
114     }
115 }
116 
VdecError(OH_AVCodec * codec,int32_t errorCode,void * userData)117 void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
118 {
119     HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
120     sample->errorCount++;
121     cout << "VdecError errorCode=" << errorCode << endl;
122     g_isRunning.store(false);
123     g_cv.notify_all();
124 }
125 
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)126 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
127 {
128     HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
129     sample->errorCount++;
130     cout << "VencError errorCode=" << errorCode << endl;
131     g_isRunning.store(false);
132     g_cv.notify_all();
133 }
134 
VencFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)135 static void VencFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
136 {
137     cout << "Format Changed" << endl;
138 }
139 
VencInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)140 static void VencInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
141 {
142     (void)codec;
143     (void)index;
144     (void)data;
145     (void)userData;
146 }
147 
VencOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)148 static void VencOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
149                                 void *userData)
150 {
151     HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample*>(userData);
152     OH_VideoEncoder_FreeOutputData(codec, index);
153     if (attr->flags & AVCODEC_BUFFER_FLAGS_EOS) {
154         g_isRunning.store(false);
155         g_cv.notify_all();
156     } else if (attr->flags != AVCODEC_BUFFER_FLAGS_CODEC_DATA) {
157         sample->frameCountEnc++;
158     }
159     if (sample->DEMUXER_FLAG) {
160         OH_AVMuxer_WriteSample(sample->muxer, sample->videoTrackID, data, *attr);
161     }
162 }
163 
clearIntqueue(std::queue<uint32_t> & q)164 static void clearIntqueue(std::queue<uint32_t> &q)
165 {
166     std::queue<uint32_t> empty;
167     swap(empty, q);
168 }
169 
PtrStep(uint32_t & bufferSize,unsigned char ** pBuffer,uint32_t size)170 void HDRCodecNdkSample::PtrStep(uint32_t &bufferSize, unsigned char **pBuffer, uint32_t size)
171 {
172     pPrereadBuffer_ += size;
173     bufferSize += size;
174     *pBuffer += size;
175 }
176 
PtrStepExtraRead(uint32_t & bufferSize,unsigned char ** pBuffer)177 void HDRCodecNdkSample::PtrStepExtraRead(uint32_t &bufferSize, unsigned char **pBuffer)
178 {
179     bufferSize -= START_CODE_SIZE;
180     *pBuffer -= START_CODE_SIZE;
181     pPrereadBuffer_ = 0;
182 }
183 
GetMpeg4BufferSize()184 void HDRCodecNdkSample::GetMpeg4BufferSize()
185 {
186     auto pBuffer = mpegUnit_->data();
187     uint32_t bufferSize = 0;
188     mpegUnit_->resize(MAX_NALU_SIZE);
189     do {
190         auto pos1 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + START_CODE_SIZE,
191             prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG4_FRAME_HEAD), std::end(MPEG4_FRAME_HEAD));
192         uint32_t size1 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos1);
193         auto pos2 = std::search(prereadBuffer_.get() + pPrereadBuffer_, prereadBuffer_.get() +
194             pPrereadBuffer_ + size1, std::begin(MPEG4_SEQUENCE_HEAD), std::end(MPEG4_SEQUENCE_HEAD));
195         uint32_t size = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos2);
196         if (size == 0) {
197             auto pos3 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + size1 + START_CODE_SIZE,
198             prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG4_FRAME_HEAD), std::end(MPEG4_FRAME_HEAD));
199             uint32_t size2 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos3);
200             if (memcpy_s(pBuffer, size2, prereadBuffer_.get() + pPrereadBuffer_, size2) != EOK) {
201                 return;
202             }
203             PtrStep(bufferSize, &pBuffer, size2);
204             if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
205                 break;
206             }
207         } else if (size1 > size) {
208             if (memcpy_s(pBuffer, size, prereadBuffer_.get() + pPrereadBuffer_, size) != EOK) {
209                 return;
210             }
211             PtrStep(bufferSize, &pBuffer, size);
212             if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
213                 break;
214             }
215         } else {
216             if (memcpy_s(pBuffer, size1, prereadBuffer_.get() + pPrereadBuffer_, size1) != EOK) {
217                 return;
218             }
219             PtrStep(bufferSize, &pBuffer, size1);
220             if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
221                 break;
222             }
223         }
224         inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
225         prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
226         pPrereadBuffer_ = START_CODE_SIZE;
227         if (memcpy_s(prereadBuffer_.get(), START_CODE_SIZE, pBuffer - START_CODE_SIZE, START_CODE_SIZE) != EOK) {
228             return;
229         }
230         PtrStepExtraRead(bufferSize, &pBuffer);
231     } while (pPrereadBuffer_ != prereadBufferSize_);
232     mpegUnit_->resize(bufferSize);
233 }
234 
GetBufferSize()235 void HDRCodecNdkSample::GetBufferSize()
236 {
237     auto pBuffer = mpegUnit_->data();
238     uint32_t bufferSize = 0;
239     mpegUnit_->resize(MAX_NALU_SIZE);
240     do {
241         auto pos1 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + START_CODE_SIZE,
242             prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG2_FRAME_HEAD), std::end(MPEG2_FRAME_HEAD));
243         uint32_t size1 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos1);
244         auto pos2 = std::search(prereadBuffer_.get() + pPrereadBuffer_, prereadBuffer_.get() +
245             pPrereadBuffer_ + size1, std::begin(MPEG2_SEQUENCE_HEAD), std::end(MPEG2_SEQUENCE_HEAD));
246         uint32_t size = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos2);
247         if (size == 0) {
248             auto pos3 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + size1 + START_CODE_SIZE,
249             prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG2_FRAME_HEAD), std::end(MPEG2_FRAME_HEAD));
250             uint32_t size2 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos3);
251             if (memcpy_s(pBuffer, size2, prereadBuffer_.get() + pPrereadBuffer_, size2) != EOK) {
252                 return;
253             }
254             PtrStep(bufferSize, &pBuffer, size2);
255             if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
256                 break;
257             }
258         } else if (size1 > size) {
259             if (memcpy_s(pBuffer, size, prereadBuffer_.get() + pPrereadBuffer_, size) != EOK) {
260                 return;
261             }
262             PtrStep(bufferSize, &pBuffer, size);
263             if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
264                 break;
265             }
266         } else {
267             if (memcpy_s(pBuffer, size1, prereadBuffer_.get() + pPrereadBuffer_, size1) != EOK) {
268                 return;
269             }
270             PtrStep(bufferSize, &pBuffer, size1);
271             if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
272                 break;
273             }
274         }
275         inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
276         prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
277         pPrereadBuffer_ = START_CODE_SIZE;
278         if (memcpy_s(prereadBuffer_.get(), START_CODE_SIZE, pBuffer - START_CODE_SIZE, START_CODE_SIZE) != EOK) {
279             return;
280         }
281         PtrStepExtraRead(bufferSize, &pBuffer);
282     } while (pPrereadBuffer_ != prereadBufferSize_);
283     mpegUnit_->resize(bufferSize);
284 }
285 
SendDataHdr(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)286 int32_t HDRCodecNdkSample::SendDataHdr(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data)
287 {
288     uint32_t bufferSize = 0;
289     int32_t result = 0;
290     OH_AVCodecBufferAttr attr;
291     static bool isFirstFrame = true;
292     (void)inFile_->read(reinterpret_cast<char *>(&bufferSize), sizeof(uint32_t));
293     if (inFile_->eof()) {
294         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
295         attr.offset = 0;
296         OH_VideoDecoder_PushInputData(codec, index, attr);
297         return 1;
298     }
299     if (isFirstFrame) {
300         attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
301         isFirstFrame = false;
302     } else {
303         attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
304     }
305     int32_t size = OH_AVMemory_GetSize(data);
306     uint8_t *avBuffer = OH_AVMemory_GetAddr(data);
307     if (avBuffer == nullptr) {
308         return 0;
309     }
310     uint8_t *fileBuffer = new uint8_t[bufferSize];
311     if (fileBuffer == nullptr) {
312         cout << "Fatal: no memory" << endl;
313         delete[] fileBuffer;
314         return 0;
315     }
316     (void)inFile_->read(reinterpret_cast<char *>(fileBuffer), bufferSize);
317     if (memcpy_s(avBuffer, size, fileBuffer, bufferSize) != EOK) {
318         delete[] fileBuffer;
319         cout << "Fatal: memcpy fail" << endl;
320         return 0;
321     }
322     delete[] fileBuffer;
323     attr.pts = GetSystemTimeUs();
324     attr.size = bufferSize;
325     attr.offset = 0;
326     result = OH_VideoDecoder_PushInputData(codec, index, attr);
327     if (result != AV_ERR_OK) {
328         cout << "push input data failed,error:" << result << endl;
329     } else {
330         inputNum++;
331     }
332     return 0;
333 }
334 
SendDataH263(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)335 int32_t HDRCodecNdkSample::SendDataH263(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data)
336 {
337     OH_AVCodecBufferAttr attr;
338     char ch[4] = {};
339     (void)inFile_->read(ch, START_CODE_SIZE);
340     if (inFile_->eof()) {
341         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
342         attr.offset = 0;
343         OH_VideoDecoder_PushInputData(codec, index, attr);
344         return 1;
345     }
346     uint32_t bufferSize = (uint32_t)(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) | ((ch[1] & 0xFF) << SIXTEEN) |
347                                      ((ch[0] & 0xFF) << TWENTY_FOUR));
348     if (bufferSize != 0) {
349         attr.flags = AVCODEC_BUFFER_FLAGS_SYNC_FRAME + AVCODEC_BUFFER_FLAGS_CODEC_DATA;
350     } else {
351         attr.offset = 0;
352         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
353         OH_VideoDecoder_PushInputData(codec, index, attr);
354         return 1;
355     }
356     int32_t size = OH_AVMemory_GetSize(data);
357     if (size < bufferSize) {
358         return 0;
359     }
360     uint8_t *avBuffer = OH_AVMemory_GetAddr(data);
361     if (avBuffer == nullptr) {
362         return 0;
363     }
364     uint8_t *fileBuffer = new uint8_t[bufferSize];
365     if (fileBuffer == nullptr) {
366         delete[] fileBuffer;
367         return 0;
368     }
369     (void)inFile_->read(reinterpret_cast<char *>(fileBuffer), bufferSize);
370     if (memcpy_s(avBuffer, size, fileBuffer, bufferSize) != EOK) {
371         delete[] fileBuffer;
372         return 0;
373     }
374     delete[] fileBuffer;
375     attr.pts = GetSystemTimeUs();
376     attr.size = bufferSize;
377     attr.offset = 0;
378     int32_t result = OH_VideoDecoder_PushInputData(codec, index, attr);
379     if (result != AV_ERR_OK) {
380         cout << "push input data failed,error:" << result << endl;
381     } else {
382         inputNum++;
383     }
384     return 0;
385 }
386 
DecAvcPushData(OH_AVMemory * data,uint32_t bufferSize,uint8_t * fileBuffer)387 int32_t DecAvcPushData(OH_AVMemory *data, uint32_t bufferSize, uint8_t *fileBuffer)
388 {
389     int32_t size = OH_AVMemory_GetSize(data);
390     if (size < bufferSize + START_CODE_SIZE) {
391         cout << "error: size < bufferSize" << endl;
392         return 1;
393     }
394     uint8_t *avBuffer = OH_AVMemory_GetAddr(data);
395     if (avBuffer == nullptr) {
396         inFile_->clear();
397         inFile_->seekg(0, ios::beg);
398         delete[] fileBuffer;
399         return 1;
400     }
401     if (memcpy_s(avBuffer, size, fileBuffer, bufferSize + START_CODE_SIZE) != EOK) {
402         delete[] fileBuffer;
403         cout << "Fatal: memcpy fail" << endl;
404         return 1;
405     }
406     delete[] fileBuffer;
407     return 0;
408 }
409 
SendDataAvc(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)410 int32_t HDRCodecNdkSample::SendDataAvc(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data)
411 {
412     OH_AVCodecBufferAttr attr;
413     char ch[4] = {};
414     (void)inFile_->read(ch, START_CODE_SIZE);
415     if (inFile_->eof()) {
416         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
417         attr.offset = 0;
418         OH_VideoDecoder_PushInputData(codec, index, attr);
419         return 1;
420     }
421     uint32_t bufferSize = (uint32_t)(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) | ((ch[1] & 0xFF) << SIXTEEN) |
422                                      ((ch[0] & 0xFF) << TWENTY_FOUR));
423     uint8_t *fileBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
424     if (fileBuffer == nullptr) {
425         delete[] fileBuffer;
426         return 0;
427     }
428     if (memcpy_s(fileBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
429         cout << "Fatal: memory copy failed" << endl;
430     }
431     (void)inFile_->read((char *)fileBuffer + START_CODE_SIZE, bufferSize);
432     if ((fileBuffer[START_CODE_SIZE] & H264_NALU_TYPE) == SPS ||
433         (fileBuffer[START_CODE_SIZE] & H264_NALU_TYPE) == PPS) {
434         attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
435     } else {
436         attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
437     }
438     if (DecAvcPushData(data, bufferSize, fileBuffer)) {
439         return 0;
440     }
441     attr.pts = GetSystemTimeUs();
442     attr.size = bufferSize + START_CODE_SIZE;
443     attr.offset = 0;
444     int32_t result = OH_VideoDecoder_PushInputData(codec, index, attr);
445     if (result != AV_ERR_OK) {
446         cout << "push input data failed,error:" << result << endl;
447     } else {
448         inputNum++;
449     }
450     return 0;
451 }
452 
DecPushData(OH_AVMemory * data,uint32_t bufferSize,uint8_t * fileBuffer)453 int32_t DecPushData(OH_AVMemory *data, uint32_t bufferSize, uint8_t *fileBuffer)
454 {
455     int32_t size = OH_AVMemory_GetSize(data);
456     if (size < bufferSize) {
457         cout << "error: size < bufferSize" << endl;
458         inFile_->clear();
459         inFile_->seekg(0, ios::beg);
460         delete[] fileBuffer;
461         return 1;
462     }
463     uint8_t *avBuffer = OH_AVMemory_GetAddr(data);
464     if (avBuffer == nullptr) {
465         cout << "avBuffer == nullptr" << endl;
466         inFile_->clear();
467         inFile_->seekg(0, ios::beg);
468         delete[] fileBuffer;
469         return 1;
470     }
471     if (memcpy_s(avBuffer, size, fileBuffer, bufferSize) != EOK) {
472         delete[] fileBuffer;
473         cout << "Fatal: memcpy fail" << endl;
474         return 1;
475     }
476     delete[] fileBuffer;
477     return 0;
478 }
479 
SendDataMpeg2(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)480 int32_t HDRCodecNdkSample::SendDataMpeg2(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data)
481 {
482     uint32_t bufferSize = 0;
483     int32_t result = 0;
484     OH_AVCodecBufferAttr attr;
485     if (inFile_->tellg() == 0) {
486         inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
487         prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
488         pPrereadBuffer_ = START_CODE_SIZE;
489     }
490     if (finishLastPush) {
491         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
492         attr.offset = 0;
493         OH_VideoDecoder_PushInputData(codec, index, attr);
494         mpegUnit_->resize(0);
495         return 1;
496     }
497     GetBufferSize();
498     bufferSize = mpegUnit_->size();
499     uint8_t *fileBuffer = nullptr;
500     if (bufferSize > 0) {
501         fileBuffer = new uint8_t[bufferSize];
502     } else {
503         delete[] fileBuffer;
504         return 0;
505     }
506     if (memcpy_s(fileBuffer, bufferSize, mpegUnit_->data(), bufferSize) != EOK) {
507         cout << "Fatal: memcpy copy fail" << endl;
508     }
509     attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
510     if (pPrereadBuffer_ == prereadBufferSize_ && inFile_->eof()) {
511         finishLastPush = true;
512     }
513     if (DecPushData(data, bufferSize, fileBuffer)) {
514         return 0;
515     }
516     attr.pts = GetSystemTimeUs();
517     attr.size = bufferSize;
518     attr.offset = 0;
519     result = OH_VideoDecoder_PushInputData(codec, index, attr);
520     if (result != AV_ERR_OK) {
521         cout << "push input data failed,error:" << result << endl;
522     } else {
523         inputNum++;
524     }
525     return 0;
526 }
527 
SendDataMpeg4(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)528 int32_t HDRCodecNdkSample::SendDataMpeg4(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data)
529 {
530     uint32_t bufferSize = 0;
531     int32_t result = 0;
532     OH_AVCodecBufferAttr attr;
533     if (inFile_->tellg() == 0) {
534         inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
535         prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
536         pPrereadBuffer_ = START_CODE_SIZE;
537     }
538     if (finishLastPush) {
539         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
540         attr.offset = 0;
541         OH_VideoDecoder_PushInputData(codec, index, attr);
542         mpegUnit_->resize(0);
543         return 1;
544     }
545     GetMpeg4BufferSize();
546     bufferSize = mpegUnit_->size();
547     if (bufferSize > MAX_WIDTH * MAX_HEIGHT << 1) {
548         return 1;
549     }
550     uint8_t *fileBuffer = nullptr;
551     if (bufferSize > 0) {
552         fileBuffer = new uint8_t[bufferSize];
553     } else {
554         delete[] fileBuffer;
555         return 0;
556     }
557     if (memcpy_s(fileBuffer, bufferSize, mpegUnit_->data(), bufferSize) != EOK) {
558         cout << "Fatal: memcpy copy fail" << endl;
559     }
560     attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
561     if (pPrereadBuffer_ == prereadBufferSize_ && inFile_->eof()) {
562         finishLastPush = true;
563     }
564     if (DecPushData(data, bufferSize, fileBuffer)) {
565         return 0;
566     }
567     attr.pts = GetSystemTimeUs();
568     attr.size = bufferSize;
569     attr.offset = 0;
570     result = OH_VideoDecoder_PushInputData(codec, index, attr);
571     if (result != AV_ERR_OK) {
572         cout << "push input data failed,error:" << result << endl;
573     } else {
574         inputNum++;
575     }
576     return 0;
577 }
578 
SendData(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)579 int32_t HDRCodecNdkSample::SendData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data)
580 {
581     switch (typeDec) {
582         case CHANNEL_0: {
583             return SendDataHdr(codec, index, data);
584         }
585         case CHANNEL_1: {
586             return SendDataH263(codec, index, data);
587         }
588         case CHANNEL_2: {
589             return SendDataAvc(codec, index, data);
590         }
591         case CHANNEL_3: {
592             return SendDataMpeg2(codec, index, data);
593         }
594         case CHANNEL_4: {
595             return SendDataMpeg4(codec, index, data);
596         }
597         default:
598             g_isRunning.store(false);
599             g_cv.notify_all();
600             return 1;
601     }
602     return 0;
603 }
604 
RepeatCallStartFlush(HDRCodecNdkSample * sample)605 static int32_t RepeatCallStartFlush(HDRCodecNdkSample *sample)
606 {
607     int32_t ret = 0;
608     sample->REPEAT_START_FLUSH_BEFORE_EOS--;
609     ret = OH_VideoEncoder_Flush(sample->venc_);
610     if (ret != AV_ERR_OK) {
611         return ret;
612     }
613     ret = OH_VideoDecoder_Flush(sample->vdec_);
614     if (ret != AV_ERR_OK) {
615         return ret;
616     }
617     sample->FlushBuffer();
618     ret = OH_VideoEncoder_Start(sample->venc_);
619     if (ret != AV_ERR_OK) {
620         return ret;
621     }
622     ret = OH_VideoDecoder_Start(sample->vdec_);
623     if (ret != AV_ERR_OK) {
624         return ret;
625     }
626     return 0;
627 }
628 
RepeatCallStartStop(HDRCodecNdkSample * sample)629 static int32_t RepeatCallStartStop(HDRCodecNdkSample *sample)
630 {
631     int32_t ret = 0;
632     sample->REPEAT_START_STOP_BEFORE_EOS--;
633     ret = OH_VideoDecoder_Stop(sample->vdec_);
634     if (ret != AV_ERR_OK) {
635         return ret;
636     }
637     ret = OH_VideoEncoder_Stop(sample->venc_);
638     if (ret != AV_ERR_OK) {
639         return ret;
640     }
641     sample->FlushBuffer();
642     ret = OH_VideoEncoder_Start(sample->venc_);
643     if (ret != AV_ERR_OK) {
644         return ret;
645     }
646     ret = OH_VideoDecoder_Start(sample->vdec_);
647     if (ret != AV_ERR_OK) {
648         return ret;
649     }
650     return 0;
651 }
652 
RepeatCallStartFlushStop(HDRCodecNdkSample * sample)653 static int32_t RepeatCallStartFlushStop(HDRCodecNdkSample *sample)
654 {
655     int32_t ret = 0;
656     sample->REPEAT_START_FLUSH_STOP_BEFORE_EOS--;
657     ret = OH_VideoEncoder_Flush(sample->venc_);
658     if (ret != AV_ERR_OK) {
659         return ret;
660     }
661     ret = OH_VideoDecoder_Flush(sample->vdec_);
662     if (ret != AV_ERR_OK) {
663         return ret;
664     }
665     ret = OH_VideoDecoder_Stop(sample->vdec_);
666     if (ret != AV_ERR_OK) {
667         return ret;
668     }
669     ret = OH_VideoEncoder_Stop(sample->venc_);
670     if (ret != AV_ERR_OK) {
671         return ret;
672     }
673     sample->FlushBuffer();
674     ret = OH_VideoEncoder_Start(sample->venc_);
675     if (ret != AV_ERR_OK) {
676         return ret;
677     }
678     ret = OH_VideoDecoder_Start(sample->vdec_);
679     if (ret != AV_ERR_OK) {
680         return ret;
681     }
682     return 0;
683 }
684 
~HDRCodecNdkSample()685 HDRCodecNdkSample::~HDRCodecNdkSample()
686 {
687     inputNum = 0;
688     Release();
689 }
690 
CreateCodec()691 int32_t HDRCodecNdkSample::CreateCodec()
692 {
693     decSignal = new VSignal();
694     if (decSignal == nullptr) {
695         return AV_ERR_UNKNOWN;
696     }
697     vdec_ = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
698     if (vdec_ == nullptr) {
699         return AV_ERR_UNKNOWN;
700     }
701 
702     venc_ = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
703     if (venc_ == nullptr) {
704         return AV_ERR_UNKNOWN;
705     }
706     return AV_ERR_OK;
707 }
708 
GetFileSize(const char * fileName)709 static int64_t GetFileSize(const char *fileName)
710 {
711     int64_t fileSize = 0;
712     if (fileName != nullptr) {
713         struct stat fileStatus {};
714         if (stat(fileName, &fileStatus) == 0) {
715             fileSize = static_cast<int64_t>(fileStatus.st_size);
716         }
717     }
718     return fileSize;
719 }
720 
CreateDemuxerVideocoder(const char * file,std::string codeName,std::string enCodeName)721 int32_t HDRCodecNdkSample::CreateDemuxerVideocoder(const char *file, std::string codeName, std::string enCodeName)
722 {
723     int trackType = 0;
724     fd = open(file, O_RDONLY);
725     outFd = open("./output.mp4", O_CREAT | O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR);
726     int64_t size = GetFileSize(file);
727     source = OH_AVSource_CreateWithFD(fd, 0, size);
728     if (!source) {
729         return AV_ERR_UNKNOWN;
730     }
731     if (CreateVideocoder(codeName, enCodeName)) {
732         return AV_ERR_UNKNOWN;
733     }
734     demuxer = OH_AVDemuxer_CreateWithSource(source);
735     muxer = OH_AVMuxer_Create(outFd, AV_OUTPUT_FORMAT_MPEG_4);
736     if (!demuxer || !muxer) {
737         return AV_ERR_UNKNOWN;
738     }
739     OH_AVFormat *sourceFormat = OH_AVSource_GetSourceFormat(source);
740     OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount);
741     OH_AVMuxer_SetFormat(muxer, sourceFormat);
742     int32_t muxTrack = 0;
743     for (int32_t index = 0; index < trackCount; index++) {
744         OH_AVDemuxer_SelectTrackByID(demuxer, index);
745         OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(source, index);
746         OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType);
747         if (trackType == MEDIA_TYPE_VID) {
748             videoTrackID = index;
749             OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_ROTATION, &DEFAULT_ROTATION);
750             OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_WIDTH, &DEFAULT_WIDTH);
751             OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_HEIGHT, &DEFAULT_HEIGHT);
752             OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_PIXEL_FORMAT, &DEFAULT_PIXEL_FORMAT);
753             OH_AVFormat_GetDoubleValue(trackFormat, OH_MD_KEY_FRAME_RATE, &DEFAULT_FRAME_RATE);
754             OH_AVFormat_SetStringValue(trackFormat, OH_MD_KEY_CODEC_MIME, MIME_TYPE);
755             OH_AVMuxer_SetRotation(muxer, DEFAULT_ROTATION);
756         } else {
757             audioTrackID = index;
758         }
759         OH_AVMuxer_AddTrack(muxer, &muxTrack, trackFormat);
760         OH_AVMuxer_SetFormat(muxer, trackFormat);
761         OH_AVFormat_Destroy(trackFormat);
762         trackFormat = nullptr;
763     }
764     return AV_ERR_OK;
765 }
766 
CreateVideocoder(std::string codeName,std::string enCodeName)767 int32_t HDRCodecNdkSample::CreateVideocoder(std::string codeName, std::string enCodeName)
768 {
769     decSignal = new VSignal();
770     if (decSignal == nullptr) {
771         return AV_ERR_UNKNOWN;
772     }
773     vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str());
774     if (vdec_ == nullptr) {
775         return AV_ERR_UNKNOWN;
776     }
777 
778     venc_ = OH_VideoEncoder_CreateByName(enCodeName.c_str());
779     if (venc_ == nullptr) {
780         return AV_ERR_UNKNOWN;
781     }
782     return AV_ERR_OK;
783 }
784 
FlushBuffer()785 void HDRCodecNdkSample::FlushBuffer()
786 {
787     unique_lock<mutex> decInLock(decSignal->inMutex_);
788     clearIntqueue(decSignal->inIdxQueue_);
789     std::queue<OH_AVMemory *>empty;
790     swap(empty, decSignal->inBufferQueue_);
791     decSignal->inCond_.notify_all();
792     inFile_->clear();
793     inFile_->seekg(0, ios::beg);
794     decInLock.unlock();
795 }
796 
RepeatCall()797 int32_t HDRCodecNdkSample::RepeatCall()
798 {
799     if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
800         return RepeatCallStartFlush(this);
801     }
802     if (REPEAT_START_STOP_BEFORE_EOS > 0) {
803         return RepeatCallStartStop(this);
804     }
805     if (REPEAT_START_FLUSH_STOP_BEFORE_EOS > 0) {
806         return RepeatCallStartFlushStop(this);
807     }
808     return 0;
809 }
810 
InputFunc()811 void HDRCodecNdkSample::InputFunc()
812 {
813     while (true) {
814         if (!g_isRunning.load()) {
815             break;
816         }
817         int32_t ret = RepeatCall();
818         if (ret != 0) {
819             cout << "repeat call failed, errcode " << ret << endl;
820             errorCount++;
821             g_isRunning.store(false);
822             g_cv.notify_all();
823             break;
824         }
825         uint32_t index;
826         unique_lock<mutex> lock(decSignal->inMutex_);
827         decSignal->inCond_.wait(lock, [this]() {
828             if (!g_isRunning.load()) {
829                 return true;
830             }
831             return decSignal->inIdxQueue_.size() > 0;
832         });
833         if (!g_isRunning.load()) {
834             break;
835         }
836         index = decSignal->inIdxQueue_.front();
837         auto buffer = decSignal->inBufferQueue_.front();
838 
839         decSignal->inIdxQueue_.pop();
840         decSignal->inBufferQueue_.pop();
841         lock.unlock();
842         if (SendData(vdec_, index, buffer) == 1)
843             break;
844     }
845 }
846 
Configure()847 int32_t HDRCodecNdkSample::Configure()
848 {
849     OH_AVFormat *format = OH_AVFormat_Create();
850     if (format == nullptr) {
851         cout << "Fatal: Failed to create format" << endl;
852         return AV_ERR_UNKNOWN;
853     }
854     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
855     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
856     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXEL_FORMAT);
857     (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
858     int ret = OH_VideoDecoder_Configure(vdec_, format);
859     if (ret != AV_ERR_OK) {
860         return ret;
861     }
862     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE);
863     ret = OH_VideoEncoder_Configure(venc_, format);
864     if (ret != AV_ERR_OK) {
865         return ret;
866     }
867     ret = OH_VideoEncoder_GetSurface(venc_, &window);
868     if (ret != AV_ERR_OK) {
869         return ret;
870     }
871     ret = OH_VideoDecoder_SetSurface(vdec_, window);
872     if (ret != AV_ERR_OK) {
873         return ret;
874     }
875     encCb_.onError = VencError;
876     encCb_.onStreamChanged = VencFormatChanged;
877     encCb_.onNeedInputData = VencInputDataReady;
878     encCb_.onNeedOutputData = VencOutputDataReady;
879     ret = OH_VideoEncoder_SetCallback(venc_, encCb_, this);
880     if (ret != AV_ERR_OK) {
881         return ret;
882     }
883     OH_AVFormat_Destroy(format);
884     decCb_.onError = VdecError;
885     decCb_.onStreamChanged = VdecFormatChanged;
886     decCb_.onNeedInputData = VdecInputDataReady;
887     decCb_.onNeedOutputData = VdecOutputDataReady;
888     return OH_VideoDecoder_SetCallback(vdec_, decCb_, this);
889 }
890 
ReConfigure()891 int32_t HDRCodecNdkSample::ReConfigure()
892 {
893     int32_t ret = OH_VideoDecoder_Reset(vdec_);
894     if (ret != AV_ERR_OK) {
895         return ret;
896     }
897     ret = OH_VideoEncoder_Reset(venc_);
898     if (ret != AV_ERR_OK) {
899         return ret;
900     }
901     FlushBuffer();
902     OH_AVFormat *format = OH_AVFormat_Create();
903     if (format == nullptr) {
904         cout<< "Fatal: Failed to create format" << endl;
905         return AV_ERR_UNKNOWN;
906     }
907     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
908     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
909     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXEL_FORMAT);
910     (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
911     ret = OH_VideoDecoder_Configure(vdec_, format);
912     if (ret != AV_ERR_OK) {
913         OH_AVFormat_Destroy(format);
914         return ret;
915     }
916     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE);
917     ret = OH_VideoEncoder_Configure(venc_, format);
918     if (ret != AV_ERR_OK) {
919         OH_AVFormat_Destroy(format);
920         return ret;
921     }
922     ret = OH_VideoDecoder_SetSurface(vdec_, window);
923     if (ret != AV_ERR_OK) {
924         OH_AVFormat_Destroy(format);
925         return ret;
926     }
927     OH_AVFormat_Destroy(format);
928     return ret;
929 }
930 
WriteAudioTrack()931 void HDRCodecNdkSample::WriteAudioTrack()
932 {
933     OH_AVMemory *buffer = nullptr;
934     buffer = OH_AVMemory_Create(AUDIO_BUFFER_SIZE);
935     bool audioWrite = true;
936     while (audioWrite) {
937         if (!g_isRunning.load()) {
938             audioWrite = false;
939             break;
940         }
941         OH_AVCodecBufferAttr info;
942         OH_AVDemuxer_ReadSample(demuxer, audioTrackID, buffer, &info);
943         if (info.flags & AVCODEC_BUFFER_FLAGS_EOS) {
944             audioWrite = false;
945             break;
946         }
947         OH_AVMuxer_WriteSample(muxer, audioTrackID, buffer, info);
948     }
949     OH_AVMemory_Destroy(buffer);
950 }
951 
StartDemuxer()952 int32_t HDRCodecNdkSample::StartDemuxer()
953 {
954     int32_t ret = 0;
955     g_isRunning.store(true);
956     OH_AVMuxer_Start(muxer);
957     ret = OH_VideoEncoder_Start(venc_);
958     if (ret != AV_ERR_OK) {
959         return ret;
960     }
961     ret = OH_VideoDecoder_Start(vdec_);
962     if (ret != AV_ERR_OK) {
963         return ret;
964     }
965     if (audioTrackID != -1) {
966         audioThread = make_unique<thread>(&HDRCodecNdkSample::WriteAudioTrack, this);
967     }
968     return 0;
969 }
Start()970 int32_t HDRCodecNdkSample::Start()
971 {
972     int32_t ret = 0;
973     prereadBuffer_ = std::make_unique<uint8_t []>(PREREAD_BUFFER_SIZE + START_CODE_SIZE);
974     mpegUnit_ = std::make_unique<std::vector<uint8_t>>(MAX_NALU_SIZE);
975     inFile_ = make_unique<ifstream>();
976     inFile_->open(INP_DIR, ios::in | ios::binary);
977     if (!inFile_->is_open()) {
978         (void)OH_VideoDecoder_Destroy(vdec_);
979         (void)OH_VideoEncoder_Destroy(venc_);
980         vdec_ = nullptr;
981         venc_ = nullptr;
982         inFile_->close();
983         inFile_.reset();
984         inFile_ = nullptr;
985         return AV_ERR_UNKNOWN;
986     }
987     g_isRunning.store(true);
988     ret = OH_VideoEncoder_Start(venc_);
989     if (ret != AV_ERR_OK) {
990         return ret;
991     }
992     ret = OH_VideoDecoder_Start(vdec_);
993     if (ret != AV_ERR_OK) {
994         return ret;
995     }
996     inputLoop_ = make_unique<thread>(&HDRCodecNdkSample::InputFunc, this);
997     if (inputLoop_ == nullptr) {
998         g_isRunning.store(false);
999         (void)OH_VideoDecoder_Stop(vdec_);
1000         ReleaseInFile();
1001         return AV_ERR_UNKNOWN;
1002     }
1003 
1004     return 0;
1005 }
1006 
StopInloop()1007 void HDRCodecNdkSample::StopInloop()
1008 {
1009     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
1010         unique_lock<mutex> lock(decSignal->inMutex_);
1011         clearIntqueue(decSignal->inIdxQueue_);
1012         g_isRunning.store(false);
1013         decSignal->inCond_.notify_all();
1014         lock.unlock();
1015         inputLoop_->join();
1016         inputLoop_.reset();
1017     }
1018 }
1019 
ReleaseInFile()1020 void HDRCodecNdkSample::ReleaseInFile()
1021 {
1022     if (inFile_ != nullptr) {
1023         if (inFile_->is_open()) {
1024             inFile_->close();
1025         }
1026         inFile_.reset();
1027         inFile_ = nullptr;
1028     }
1029 }
1030 
WaitForEos()1031 void HDRCodecNdkSample::WaitForEos()
1032 {
1033     std::mutex mtx;
1034     unique_lock<mutex> lock(mtx);
1035     g_cv.wait(lock, []() {
1036         return !(g_isRunning.load());
1037     });
1038     if (audioThread) {
1039         audioThread->join();
1040     }
1041     if (inputLoop_) {
1042         inputLoop_->join();
1043     }
1044     OH_VideoDecoder_Stop(vdec_);
1045     OH_VideoEncoder_Stop(venc_);
1046 }
1047 
Release()1048 int32_t HDRCodecNdkSample::Release()
1049 {
1050     if (decSignal != nullptr) {
1051         delete decSignal;
1052         decSignal = nullptr;
1053     }
1054     if (vdec_ != nullptr) {
1055         OH_VideoDecoder_Destroy(vdec_);
1056         vdec_ = nullptr;
1057     }
1058     if (venc_ != nullptr) {
1059         OH_VideoEncoder_Destroy(venc_);
1060         venc_ = nullptr;
1061     }
1062     if (muxer != nullptr) {
1063         OH_AVMuxer_Destroy(muxer);
1064         muxer = nullptr;
1065     }
1066     if (demuxer != nullptr) {
1067         OH_AVDemuxer_Destroy(demuxer);
1068         demuxer = nullptr;
1069     }
1070     if (source != nullptr) {
1071         OH_AVSource_Destroy(source);
1072         source = nullptr;
1073     }
1074     if (fd > 0) {
1075         close(fd);
1076         fd = -1;
1077     }
1078     if (outFd > 0) {
1079         close(outFd);
1080         outFd = -1;
1081     }
1082     return 0;
1083 }