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
16 #include "avcodec_bitstream_dump.h"
17 #include <fstream>
18 #include <unistd.h>
19 #include <malloc.h>
20 #include <sys/time.h>
21 #include <sstream>
22 #include <map>
23 #include <iomanip>
24 #include "avcodec_log.h"
25
26 namespace {
27 constexpr ::OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecBitStreamDumper"};
28 constexpr int32_t FILE_MAX = 100;
29 constexpr int32_t FILE_BIT_STREAM_MAX = 1000;
30 constexpr uint8_t HEX_WIDTH = 2;
31
32 const std::map<OHOS::MediaAVCodec::BitStreamDumpType, std::string_view> BIT_STREAM_DUMP_MAP = {
33 { OHOS::MediaAVCodec::BitStreamDumpType::BIT_STREAM_DUMP_TYPE_DEFAULT, "Default" },
34 { OHOS::MediaAVCodec::BitStreamDumpType::BIT_STREAM_DUMP_TYPE_VCODEC, "Video_Codec" },
35 { OHOS::MediaAVCodec::BitStreamDumpType::BIT_STREAM_DUMP_TYPE_ACODEC, "Audio_Codec" },
36 { OHOS::MediaAVCodec::BitStreamDumpType::BIT_STREAM_DUMP_TYPE_MUXER, "Muxer" },
37 { OHOS::MediaAVCodec::BitStreamDumpType::BIT_STREAM_DUMP_TYPE_DEMUXER, "Demuxer" },
38 { OHOS::MediaAVCodec::BitStreamDumpType::BIT_STREAM_DUMP_TYPE_SOURCE, "Source" },
39 };
40 }
41
42 namespace OHOS {
43 namespace MediaAVCodec {
GetInstance()44 AVCodecBitStreamDumper &AVCodecBitStreamDumper::GetInstance()
45 {
46 static AVCodecBitStreamDumper avcodecBitStreamDumper;
47 return avcodecBitStreamDumper;
48 }
49
AVCodecBitStreamDumper()50 AVCodecBitStreamDumper::AVCodecBitStreamDumper() {}
51
~AVCodecBitStreamDumper()52 AVCodecBitStreamDumper::~AVCodecBitStreamDumper()
53 {
54 {
55 std::unique_lock<std::mutex> lock(mutex_);
56 isExit_ = true;
57 cond_.notify_all();
58 }
59 if (thread_ != nullptr && thread_->joinable()) {
60 thread_->join();
61 }
62 }
63
AddNewBitStream(BitStreamDumpType type,const std::string & name,const uint32_t index,const uint32_t size,std::string & bitstreamStr)64 static void AddNewBitStream(BitStreamDumpType type, const std::string &name,
65 const uint32_t index, const uint32_t size, std::string &bitstreamStr)
66 {
67 struct timeval time = {};
68 (void)gettimeofday(&time, nullptr);
69 int64_t second = time.tv_sec % 60;
70 int64_t allMinute = time.tv_sec / 60;
71 int64_t minute = allMinute % 60;
72 int64_t hour = allMinute / 60 % 24;
73 int64_t mSecond = time.tv_usec / 1000;
74
75 std::stringstream outStream;
76 outStream << "### ";
77 outStream << "[" << BIT_STREAM_DUMP_MAP.at(type).data() << "] ";
78 outStream << "[" << name << "] ";
79 outStream << "[" << "Index: " << std::to_string(index) << "] ";
80 outStream << "[" << "Size: " << std::to_string(size) << "] ";
81 outStream << "[" << std::to_string(hour) << ":" << std::to_string(minute) << ":" << std::to_string(second) <<
82 "." << std::to_string(mSecond) << "] ";
83 outStream << "[" << "pid: " << std::to_string(getpid()) << "] ";
84 outStream << "[" << "tid: " << std::to_string(gettid()) << "] ";
85 outStream << "[" << "uid: " << std::to_string(getuid()) << "] ";
86 outStream << std::endl;
87
88 bitstreamStr += outStream.str();
89 }
90
SaveBitStream(BitStreamDumpType type,const std::string & name,const uint32_t index,const uint8_t * buffer,const uint32_t size)91 void AVCodecBitStreamDumper::SaveBitStream(BitStreamDumpType type, const std::string &name,
92 const uint32_t index, const uint8_t* buffer, const uint32_t size)
93 {
94 std::unique_lock<std::mutex> lock(mutex_);
95 if (!isEnable_) {
96 if (thread_ != nullptr) {
97 AVCODEC_LOGI("Bitstream dumper shutdown.");
98 thread_.reset();
99 }
100 return;
101 }
102
103 if (thread_ == nullptr) {
104 AVCODEC_LOGI("Bitstream dumper init");
105 thread_ = std::make_unique<std::thread>(&AVCodecBitStreamDumper::TaskProcessor, this);
106 }
107
108 std::stringstream outStream;
109 outStream << std::hex << std::uppercase << std::setfill('0');
110 for (uint32_t idx = 0; idx < size; idx++) {
111 outStream << std::setw(HEX_WIDTH) << (int)(buffer[idx]) << " ";
112 }
113
114 AddNewBitStream(type, name, index, size, bitstreamString_);
115
116 bitstreamString_ += outStream.str();
117 bitstreamString_ += "\n\n";
118
119 isDump_ = true;
120
121 bitStreamCount_++;
122 if (bitStreamCount_ >= FILE_BIT_STREAM_MAX) {
123 cond_.notify_all();
124 }
125 }
126
SwitchEnable()127 bool AVCodecBitStreamDumper::SwitchEnable()
128 {
129 isEnable_ = !isEnable_;
130 std::string status = isEnable_ ? "Enable" : "Disable";
131 AVCODEC_LOGI("Bitstream dumper on status: %{public}s", status.c_str());
132 return isEnable_;
133 }
134
TaskProcessor()135 void AVCodecBitStreamDumper::TaskProcessor()
136 {
137 pthread_setname_np(pthread_self(), "AVCodecBitStreamDumperTask");
138 (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
139 (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
140 while (true) {
141 std::string temp;
142 int32_t lineCount = 0;
143 {
144 std::unique_lock<std::mutex> lock(mutex_);
145 if (isExit_) {
146 return;
147 }
148 static constexpr int32_t timeout = 5; // every 5 second have a log
149 cond_.wait_for(lock, std::chrono::seconds(timeout),
150 [this] {
151 return isExit_ || isDump_ || bitStreamCount_ >= FILE_BIT_STREAM_MAX || !bitstreamString_.empty();
152 });
153 isDump_ = false;
154 lineCount = bitStreamCount_;
155 bitStreamCount_ = bitStreamCount_ >= FILE_BIT_STREAM_MAX ? 0 : bitStreamCount_;
156 swap(bitstreamString_, temp);
157 }
158
159 std::string file = "/data/media/av_codec/bitstream_dump/";
160 file += std::to_string(getpid());
161 file += "_bitstream_dump_";
162 file += std::to_string(fileCount_) + ".log";
163
164 std::ofstream ofStream;
165 if (isNewFile_) {
166 ofStream.open(file, std::ios::out | std::ios::trunc);
167 } else {
168 ofStream.open(file, std::ios::out | std::ios::app);
169 }
170 if (!ofStream.is_open()) {
171 AVCODEC_LOGE("Open bitstream dump file failed");
172 continue;
173 }
174 isNewFile_ = false;
175 if (lineCount >= FILE_BIT_STREAM_MAX) {
176 isNewFile_ = true;
177 fileCount_++;
178 fileCount_ = fileCount_ > FILE_MAX ? 0 : fileCount_;
179 }
180
181 AVCODEC_LOGI("Save bitstream");
182 ofStream.write(temp.c_str(), temp.size());
183 ofStream.close();
184 }
185 }
186 } // namespace MediaAVCodec
187 } // namespace OHOS