• 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 
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