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 "av_thumbnail_generator.h"
17
18 #include "buffer/avbuffer_common.h"
19 #include "common/media_source.h"
20 #include "ibuffer_consumer_listener.h"
21 #include "graphic_common_c.h"
22 #include "media_errors.h"
23 #include "media_log.h"
24 #include "media_description.h"
25 #include "meta/meta.h"
26 #include "meta/meta_key.h"
27 #include "plugin/plugin_time.h"
28 #include "sync_fence.h"
29 #include "uri_helper.h"
30
31 #include "v1_0/cm_color_space.h"
32 #include "v1_0/hdr_static_metadata.h"
33 #include "v1_0/buffer_handle_meta_key_type.h"
34
35 namespace {
36 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_METADATA, "AVThumbnailGenerator" };
37 }
38
39 namespace OHOS {
40 namespace Media {
41 using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
42 using FileType = OHOS::Media::Plugins::FileType;
43 constexpr float BYTES_PER_PIXEL_YUV = 1.5;
44 constexpr int32_t RATE_UV = 2;
45 constexpr int32_t SHIFT_BITS_P010_2_NV12 = 8;
46 constexpr double VIDEO_FRAME_RATE = 2000.0;
47 constexpr int32_t MAX_WAIT_TIME_SECOND = 3;
48 constexpr uint32_t REQUEST_BUFFER_TIMEOUT = 0; // Requesting buffer overtimes 0ms means no retry
49 constexpr uint32_t ERROR_AGAIN_SLEEP_TIME_US = 1000;
50 const std::string AV_THUMBNAIL_GENERATOR_INPUT_BUFFER_QUEUE_NAME = "AVThumbnailGeneratorInputBufferQueue";
51
52 class ThumnGeneratorCodecCallback : public OHOS::MediaAVCodec::MediaCodecCallback {
53 public:
ThumnGeneratorCodecCallback(std::shared_ptr<AVThumbnailGenerator> generator)54 explicit ThumnGeneratorCodecCallback(std::shared_ptr<AVThumbnailGenerator> generator) : generator_(generator) {}
55
56 ~ThumnGeneratorCodecCallback() = default;
57
OnError(MediaAVCodec::AVCodecErrorType errorType,int32_t errorCode)58 void OnError(MediaAVCodec::AVCodecErrorType errorType, int32_t errorCode) override
59 {
60 if (auto generator = generator_.lock()) {
61 generator->OnError(errorType, errorCode);
62 } else {
63 MEDIA_LOGE("invalid AVThumbnailGenerator");
64 }
65 }
66
OnOutputFormatChanged(const MediaAVCodec::Format & format)67 void OnOutputFormatChanged(const MediaAVCodec::Format &format) override
68 {
69 if (auto generator = generator_.lock()) {
70 generator->OnOutputFormatChanged(format);
71 } else {
72 MEDIA_LOGE("invalid AVThumbnailGenerator");
73 }
74 }
75
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)76 void OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer) override
77 {
78 if (auto generator = generator_.lock()) {
79 generator->OnInputBufferAvailable(index, buffer);
80 } else {
81 MEDIA_LOGE("invalid AVThumbnailGenerator");
82 }
83 }
84
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)85 void OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer) override
86 {
87 if (auto generator = generator_.lock()) {
88 generator->OnOutputBufferAvailable(index, buffer);
89 } else {
90 MEDIA_LOGE("invalid AVThumbnailGenerator");
91 }
92 }
93
94 private:
95 std::weak_ptr<AVThumbnailGenerator> generator_;
96 };
97
98 class ThumbnailGeneratorAVBufferAvailableListener : public OHOS::Media::IConsumerListener {
99 public:
ThumbnailGeneratorAVBufferAvailableListener(std::shared_ptr<AVThumbnailGenerator> generator)100 explicit ThumbnailGeneratorAVBufferAvailableListener(std::shared_ptr<AVThumbnailGenerator> generator)
101 : generator_(generator)
102 {
103 }
104
OnBufferAvailable()105 void OnBufferAvailable() override
106 {
107 if (auto generator = generator_.lock()) {
108 generator->AcquireAvailableInputBuffer();
109 } else {
110 MEDIA_LOGE("invalid AVThumbnailGenerator");
111 }
112 }
113 private:
114 std::weak_ptr<AVThumbnailGenerator> generator_;
115 };
116
AVThumbnailGenerator(std::shared_ptr<MediaDemuxer> & mediaDemuxer,int32_t appUid,int32_t appPid,uint32_t appTokenId,uint64_t appFullTokenId)117 AVThumbnailGenerator::AVThumbnailGenerator(std::shared_ptr<MediaDemuxer> &mediaDemuxer, int32_t appUid, int32_t appPid,
118 uint32_t appTokenId, uint64_t appFullTokenId) : mediaDemuxer_(mediaDemuxer), appUid_(appUid), appPid_(appPid),
119 appTokenId_(appTokenId), appFullTokenId_(appFullTokenId)
120 {
121 MEDIA_LOGI("Constructor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
122 }
123
~AVThumbnailGenerator()124 AVThumbnailGenerator::~AVThumbnailGenerator()
125 {
126 MEDIA_LOGI("Destructor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
127 Destroy();
128 }
129
OnError(MediaAVCodec::AVCodecErrorType errorType,int32_t errorCode)130 void AVThumbnailGenerator::OnError(MediaAVCodec::AVCodecErrorType errorType, int32_t errorCode)
131 {
132 MEDIA_LOGE("OnError errorType:%{public}d, errorCode:%{public}d", static_cast<int32_t>(errorType), errorCode);
133 {
134 std::scoped_lock lock(mutex_, queueMutex_);
135 stopProcessing_ = true;
136 }
137 cond_.notify_all();
138 bufferAvailableCond_.notify_all();
139 }
140
InitDecoder()141 Status AVThumbnailGenerator::InitDecoder()
142 {
143 MEDIA_LOGD("Init decoder start.");
144 if (videoDecoder_ != nullptr) {
145 MEDIA_LOGD("AVThumbnailGenerator InitDecoder already.");
146 Format format;
147 format.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, VIDEO_FRAME_RATE);
148 videoDecoder_->SetParameter(format);
149 videoDecoder_->Start();
150 return Status::OK;
151 }
152 Format format;
153 int32_t ret = 0;
154 std::shared_ptr<Media::Meta> callerInfo = std::make_shared<Media::Meta>();
155 callerInfo->SetData(Media::Tag::AV_CODEC_FORWARD_CALLER_PID, appPid_);
156 callerInfo->SetData(Media::Tag::AV_CODEC_FORWARD_CALLER_UID, appUid_);
157 callerInfo->SetData(Media::Tag::AV_CODEC_FORWARD_CALLER_PROCESS_NAME, appName_);
158 format.SetMeta(callerInfo);
159 ret = MediaAVCodec::VideoDecoderFactory::CreateByMime(trackMime_, format, videoDecoder_);
160 MEDIA_LOGI("VideoDecoderAdapter::Init CreateByMime errorCode %{public}d", ret);
161 CHECK_AND_RETURN_RET_LOG(videoDecoder_ != nullptr, Status::ERROR_NO_MEMORY, "Create videoDecoder_ is nullptr");
162 MEDIA_LOGI("appUid: %{public}d, appPid: %{public}d, appName: %{public}s", appUid_, appPid_, appName_.c_str());
163 CHECK_AND_RETURN_RET_LOG(trackInfo_ != nullptr, Status::ERROR_NULL_POINTER, "track info init failed");
164 Format trackFormat{};
165 if (fileType_ == FileType::AVI) {
166 trackInfo_->SetData(Tag::MEDIA_FILE_TYPE, FileType::AVI);
167 }
168 trackFormat.SetMeta(trackInfo_);
169 trackFormat.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width_);
170 trackFormat.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height_);
171 MEDIA_LOGI("0x%{public}06" PRIXPTR " Init decoder trackFormat width:%{public}d, height:%{public}d",
172 FAKE_POINTER(this), width_, height_);
173 trackFormat.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT,
174 static_cast<int32_t>(Plugins::VideoPixelFormat::NV12));
175 trackFormat.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, VIDEO_FRAME_RATE);
176 videoDecoder_->Configure(trackFormat);
177 std::shared_ptr<MediaAVCodec::MediaCodecCallback> mediaCodecCallback =
178 std::make_shared<ThumnGeneratorCodecCallback>(shared_from_this());
179 videoDecoder_->SetCallback(mediaCodecCallback);
180 videoDecoder_->Prepare();
181 auto res = videoDecoder_->Start();
182 CHECK_AND_RETURN_RET(res == MSERR_OK, Status::ERROR_WRONG_STATE);
183 return Status::OK;
184 }
185
Init()186 int32_t AVThumbnailGenerator::Init()
187 {
188 CHECK_AND_RETURN_RET_LOG(inputBufferQueue_ == nullptr, MSERR_OK, "InputBufferQueue already create");
189
190 inputBufferQueue_ = AVBufferQueue::Create(0,
191 MemoryType::UNKNOWN_MEMORY, AV_THUMBNAIL_GENERATOR_INPUT_BUFFER_QUEUE_NAME, true);
192 CHECK_AND_RETURN_RET_LOG(inputBufferQueue_ != nullptr, MSERR_NO_MEMORY, "BufferQueue is nullptr");
193
194 inputBufferQueueProducer_ = inputBufferQueue_->GetProducer();
195 CHECK_AND_RETURN_RET_LOG(inputBufferQueueProducer_ != nullptr, MSERR_UNKNOWN, "QueueProducer is nullptr");
196
197 inputBufferQueueConsumer_ = inputBufferQueue_->GetConsumer();
198 CHECK_AND_RETURN_RET_LOG(inputBufferQueueConsumer_ != nullptr, MSERR_UNKNOWN, "QueueConsumer is nullptr");
199
200 sptr<IConsumerListener> listener = new ThumbnailGeneratorAVBufferAvailableListener(shared_from_this());
201 CHECK_AND_RETURN_RET_LOG(listener != nullptr, MSERR_NO_MEMORY, "listener is nullptr");
202 inputBufferQueueConsumer_->SetBufferAvailableListener(listener);
203
204 readTask_ = std::make_unique<Task>(std::string("AVThumbReadLoop"));
205 CHECK_AND_RETURN_RET_LOG(readTask_ != nullptr, MSERR_NO_MEMORY, "Task is nullptr");
206
207 readTask_->RegisterJob([this] {return ReadLoop();});
208 readTask_->Start();
209
210 return MSERR_OK;
211 }
212
SetClientBundleName(std::string appName)213 void AVThumbnailGenerator::SetClientBundleName(std::string appName)
214 {
215 appName_ = appName;
216 return;
217 }
218
AcquireAvailableInputBuffer()219 void AVThumbnailGenerator::AcquireAvailableInputBuffer()
220 {
221 CHECK_AND_RETURN_LOG(inputBufferQueueConsumer_ != nullptr, "QueueConsumer is nullptr");
222
223 std::shared_ptr<AVBuffer> filledInputBuffer;
224 Status ret = inputBufferQueueConsumer_->AcquireBuffer(filledInputBuffer);
225 CHECK_AND_RETURN_LOG(ret == Status::OK, "AcquireBuffer fail");
226
227 if (fileType_ == FileType::AVI) {
228 GetInputBufferDts(filledInputBuffer);
229 }
230 CHECK_AND_RETURN_LOG(filledInputBuffer != nullptr && filledInputBuffer->meta_ != nullptr,
231 "filledInputBuffer is invalid.");
232 uint32_t index;
233 CHECK_AND_RETURN_LOG(filledInputBuffer->meta_->GetData(Tag::BUFFER_INDEX, index), "get index failed.");
234
235 CHECK_AND_RETURN_LOG(videoDecoder_ != nullptr, "videoDecoder_ is nullptr.");
236 if (videoDecoder_->QueueInputBuffer(index) != ERR_OK) {
237 MEDIA_LOGE("QueueInputBuffer failed, index: %{public}u, bufferid: %{public}" PRIu64
238 ", pts: %{public}" PRIu64", flag: %{public}u", index, filledInputBuffer->GetUniqueId(),
239 filledInputBuffer->pts_, filledInputBuffer->flag_);
240 } else {
241 MEDIA_LOGD("QueueInputBuffer success, index: %{public}u, bufferid: %{public}" PRIu64
242 ", pts: %{public}" PRIu64", flag: %{public}u", index, filledInputBuffer->GetUniqueId(),
243 filledInputBuffer->pts_, filledInputBuffer->flag_);
244 }
245 }
246
GetInputBufferDts(std::shared_ptr<AVBuffer> & inputBuffer)247 void AVThumbnailGenerator::GetInputBufferDts(std::shared_ptr<AVBuffer> &inputBuffer)
248 {
249 CHECK_AND_RETURN_NOLOG(inputBuffer != nullptr);
250 std::unique_lock<std::mutex> lock(dtsQueMutex_);
251 inputBufferDtsQue_.push_back(inputBuffer->dts_);
252 MEDIA_LOGD("Inputbuffer DTS: %{public}" PRId64 " dtsQue_ size: %{public}" PRIu64,
253 inputBuffer->dts_, static_cast<uint64_t>(inputBufferDtsQue_.size()));
254 }
255
InitMediaInfoFromGlobalMeta()256 void AVThumbnailGenerator::InitMediaInfoFromGlobalMeta()
257 {
258 auto meta = mediaDemuxer_->GetGlobalMetaInfo();
259 CHECK_AND_RETURN_LOG(meta != nullptr, "Global info is nullptr");
260 (void)meta->Get<Tag::MEDIA_DURATION>(duration_);
261 MEDIA_LOGI("%{public}" PRId64, duration_);
262 CHECK_AND_RETURN_NOLOG(meta->GetData(Tag::MEDIA_FILE_TYPE, fileType_));
263 MEDIA_LOGI("file type is: %{public}" PRId32, static_cast<int32_t>(fileType_));
264 }
265
GetVideoTrackInfo()266 std::shared_ptr<Meta> AVThumbnailGenerator::GetVideoTrackInfo()
267 {
268 CHECK_AND_RETURN_RET(trackInfo_ == nullptr, trackInfo_);
269 CHECK_AND_RETURN_RET_LOG(mediaDemuxer_ != nullptr, nullptr, "GetTargetTrackInfo demuxer is nullptr");
270 InitMediaInfoFromGlobalMeta();
271 std::vector<std::shared_ptr<Meta>> trackInfos = mediaDemuxer_->GetStreamMetaInfo();
272 size_t trackCount = trackInfos.size();
273 CHECK_AND_RETURN_RET_LOG(trackCount > 0, nullptr, "GetTargetTrackInfo trackCount is invalid");
274 for (size_t index = 0; index < trackCount; index++) {
275 CHECK_AND_CONTINUE_LOG(trackInfos[index] != nullptr, "trackInfos[%{public}zu] is nullptr", index);
276 if (!(trackInfos[index]->GetData(Tag::MIME_TYPE, trackMime_))) {
277 MEDIA_LOGW("GetTargetTrackInfo get mime type failed %{public}s", trackMime_.c_str());
278 continue;
279 }
280 if (trackMime_.find("video/") == 0) {
281 Plugins::MediaType mediaType;
282 CHECK_AND_RETURN_RET_LOG(trackInfos[index]->GetData(Tag::MEDIA_TYPE, mediaType), nullptr,
283 "GetTargetTrackInfo failed to get mediaType, index:%{public}zu", index);
284 CHECK_AND_RETURN_RET_LOG(
285 mediaType == Plugins::MediaType::VIDEO, nullptr,
286 "GetTargetTrackInfo mediaType is not video, index:%{public}zu, mediaType:%{public}d", index,
287 static_cast<int32_t>(mediaType));
288 CHECK_AND_RETURN_RET_LOG(trackInfos[index]->Get<Tag::VIDEO_FRAME_RATE>(frameRate_) && frameRate_ > 0,
289 nullptr, "failed to get video frame rate");
290 trackIndex_ = index;
291 MEDIA_LOGI("0x%{public}06" PRIXPTR " GetTrackInfo success trackIndex_:%{public}zu, trackMime_:%{public}s",
292 FAKE_POINTER(this), trackIndex_, trackMime_.c_str());
293 trackInfos[index]->Get<Tag::VIDEO_ROTATION>(rotation_);
294 trackInfos[index]->Get<Tag::VIDEO_ORIENTATION_TYPE>(orientation_);
295 MEDIA_LOGI("rotation is %{public}d, orientation is %{public}d", static_cast<int32_t>(rotation_),
296 static_cast<int32_t>(orientation_));
297 return trackInfos[trackIndex_];
298 }
299 }
300 MEDIA_LOGW("GetTargetTrackInfo FAILED.");
301 return nullptr;
302 }
303
OnOutputFormatChanged(const MediaAVCodec::Format & format)304 void AVThumbnailGenerator::OnOutputFormatChanged(const MediaAVCodec::Format &format)
305 {
306 MEDIA_LOGD("OnOutputFormatChanged");
307 outputFormat_ = format;
308 int32_t width = 0;
309 int32_t height = 0;
310 bool hasWidth = format.GetIntValue(Tag::VIDEO_PIC_WIDTH, width);
311 bool hasHeight = format.GetIntValue(Tag::VIDEO_PIC_HEIGHT, height);
312 CHECK_AND_RETURN_LOG(hasWidth && hasHeight, "OutputFormat doesn't have width or height");
313 width_ = width;
314 height_ = height;
315 }
316
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)317 void AVThumbnailGenerator::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
318 {
319 CHECK_AND_RETURN_LOG(buffer != nullptr && buffer->meta_ != nullptr, "meta_ is nullptr.");
320
321 MEDIA_LOGD("OnInputBufferAvailable enter. index: %{public}u, bufferid: %{public}" PRIu64", pts: %{public}" PRIu64
322 ", flag: %{public}u", index, buffer->GetUniqueId(), buffer->pts_, buffer->flag_);
323
324 buffer->meta_->SetData(Tag::BUFFER_INDEX, index);
325
326 CHECK_AND_RETURN_LOG(inputBufferQueueConsumer_ != nullptr, "QueueConsumer is nullptr");
327
328 if (stopProcessing_.load() || hasFetchedFrame_.load() || readErrorFlag_.load()) {
329 MEDIA_LOGD("stop or has fetched frame, need not queue input buffer");
330 return;
331 }
332
333 {
334 std::unique_lock<std::mutex> lock(queueMutex_);
335 if (inputBufferQueueConsumer_->IsBufferInQueue(buffer)) {
336 if (inputBufferQueueConsumer_->ReleaseBuffer(buffer) != Status::OK) {
337 MEDIA_LOGE("IsBufferInQueue ReleaseBuffer failed. index: %{public}u, bufferid: %{public}" PRIu64
338 ", pts: %{public}" PRIu64", flag: %{public}u", index, buffer->GetUniqueId(),
339 buffer->pts_, buffer->flag_);
340 return;
341 } else {
342 MEDIA_LOGD("IsBufferInQueue ReleaseBuffer success. index: %{public}u, bufferid: %{public}" PRIu64
343 ", pts: %{public}" PRIu64", flag: %{public}u", index, buffer->GetUniqueId(),
344 buffer->pts_, buffer->flag_);
345 }
346 } else {
347 uint32_t size = inputBufferQueueConsumer_->GetQueueSize() + 1;
348 MEDIA_LOGI("AttachBuffer enter. index: %{public}u, size: %{public}u , bufferid: %{public}" PRIu64,
349 index, size, buffer->GetUniqueId());
350 inputBufferQueueConsumer_->SetQueueSizeAndAttachBuffer(size, buffer, false);
351 bufferVector_.push_back(buffer);
352 }
353 isBufferAvailable_ = true;
354 }
355 bufferAvailableCond_.notify_all();
356 }
357
ReadLoop()358 int64_t AVThumbnailGenerator::ReadLoop()
359 {
360 std::shared_ptr<AVBuffer> emptyBuffer = nullptr;
361 {
362 std::unique_lock<std::mutex> lock(queueMutex_);
363 bufferAvailableCond_.wait(lock, [this] {
364 return stopProcessing_.load() ||
365 (!hasFetchedFrame_.load() && !readErrorFlag_.load() && isBufferAvailable_.load());
366 });
367
368 CHECK_AND_RETURN_RET_LOG(!stopProcessing_.load(), StopTask(), "Stop Readloop");
369
370 CHECK_AND_RETURN_RET_LOG(inputBufferQueueProducer_ != nullptr, StopTask(), "QueueProducer is nullptr");
371
372 AVBufferConfig avBufferConfig;
373 auto res = inputBufferQueueProducer_->RequestBuffer(emptyBuffer, avBufferConfig, REQUEST_BUFFER_TIMEOUT);
374 if (res != Status::OK) {
375 isBufferAvailable_ = false;
376 return 0;
377 }
378 }
379
380 CHECK_AND_RETURN_RET_LOG(mediaDemuxer_ != nullptr, StopTask(), "mediaDemuxer is nullptr");
381
382 auto readSampleRes = mediaDemuxer_->ReadSample(trackIndex_, emptyBuffer);
383 if (readSampleRes != Status::OK && readSampleRes != Status::END_OF_STREAM && readSampleRes != Status::ERROR_AGAIN) {
384 {
385 std::unique_lock<std::mutex> lock(mutex_);
386 readErrorFlag_ = true;
387 }
388 cond_.notify_all();
389 inputBufferQueueProducer_->PushBuffer(emptyBuffer, false);
390 return 0;
391 }
392 if (readSampleRes == Status::ERROR_AGAIN) {
393 inputBufferQueueProducer_->PushBuffer(emptyBuffer, false);
394 return ERROR_AGAIN_SLEEP_TIME_US;
395 }
396 if (fileType_ == FileType::AVI) {
397 SetDemuxerOutputBufferPts(emptyBuffer);
398 }
399 inputBufferQueueProducer_->PushBuffer(emptyBuffer, true);
400 return 0;
401 }
402
SetDemuxerOutputBufferPts(std::shared_ptr<AVBuffer> & outputBuffer)403 void AVThumbnailGenerator::SetDemuxerOutputBufferPts(std::shared_ptr<AVBuffer> &outputBuffer)
404 {
405 CHECK_AND_RETURN_NOLOG(outputBuffer != nullptr);
406 MEDIA_LOGD("OutputBuffer PTS: %{public}" PRId64 " DTS: %{public}" PRId64, outputBuffer->pts_, outputBuffer->dts_);
407 outputBuffer->pts_ = outputBuffer->dts_;
408 }
409
StopTask()410 int64_t AVThumbnailGenerator::StopTask()
411 {
412 if (readTask_ != nullptr) {
413 readTask_->Stop();
414 }
415 return 0;
416 }
417
SetDecoderOutputBufferPts(std::shared_ptr<AVBuffer> & outputBuffer)418 void AVThumbnailGenerator::SetDecoderOutputBufferPts(std::shared_ptr<AVBuffer> &outputBuffer)
419 {
420 CHECK_AND_RETURN_NOLOG(outputBuffer != nullptr);
421 std::unique_lock<std::mutex> lock(dtsQueMutex_);
422 if (!inputBufferDtsQue_.empty()) {
423 outputBuffer->pts_ = inputBufferDtsQue_.front();
424 inputBufferDtsQue_.pop_front();
425 MEDIA_LOGD("DecOutputbuf PTS: %{public}" PRId64 " dtsQue_ size: %{public}" PRIu64,
426 outputBuffer->pts_, static_cast<uint64_t>(inputBufferDtsQue_.size()));
427 } else {
428 MEDIA_LOGW("DtsQue_ is empty. DecOutputbuf DTS: %{public}" PRId64, outputBuffer->dts_);
429 outputBuffer->pts_ = outputBuffer->dts_;
430 }
431 }
432
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)433 void AVThumbnailGenerator::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
434 {
435 if (fileType_ == FileType::AVI) {
436 SetDecoderOutputBufferPts(buffer);
437 }
438 CHECK_AND_RETURN_LOG(buffer != nullptr, "buffer is nullptr");
439 MEDIA_LOGD("OnOutputBufferAvailable index:%{public}u , pts %{public}" PRId64, index, buffer->pts_);
440 CHECK_AND_RETURN_LOG(videoDecoder_ != nullptr, "Video decoder not exist");
441 bool isEosBuffer = buffer->flag_ & (uint32_t)(AVBufferFlag::EOS);
442 bool isValidBuffer = buffer != nullptr && buffer->memory_ != nullptr &&
443 (buffer->memory_->GetSize() != 0 || buffer->memory_->GetSurfaceBuffer() != nullptr || isEosBuffer);
444 bool isValidState = !hasFetchedFrame_.load() && !stopProcessing_.load();
445 if (!isValidBuffer || !isValidState) {
446 MEDIA_LOGW("isValidBuffer %{public}d isValidState %{public}d", isValidBuffer, isValidState);
447 videoDecoder_->ReleaseOutputBuffer(index, false);
448 return;
449 }
450 bool isClosest = seekMode_ == Plugins::SeekMode::SEEK_CLOSEST;
451 bool isAvailableFrame = !isClosest || buffer->pts_ >= seekTime_ || isEosBuffer;
452 if (!isAvailableFrame) {
453 videoDecoder_->ReleaseOutputBuffer(bufferIndex_, false);
454 bufferIndex_ = index;
455 avBuffer_ = buffer;
456 return;
457 }
458
459 {
460 std::unique_lock<std::mutex> lock(mutex_);
461 hasFetchedFrame_ = true;
462 }
463 if (isClosest && avBuffer_ != nullptr) {
464 int64_t preDiff = seekTime_ - avBuffer_->pts_;
465 int64_t nextDiff = buffer->pts_ - seekTime_;
466 if (preDiff > nextDiff && !(buffer->flag_ & (uint32_t)(AVBufferFlag::EOS))) {
467 videoDecoder_->ReleaseOutputBuffer(bufferIndex_, false);
468 bufferIndex_ = index;
469 avBuffer_ = buffer;
470 } else {
471 videoDecoder_->ReleaseOutputBuffer(index, false);
472 }
473 } else {
474 bufferIndex_ = index;
475 avBuffer_ = buffer;
476 }
477 MEDIA_LOGI("dstTime %{public}" PRId64 " resTime %{public}" PRId64, seekTime_, buffer->pts_);
478 cond_.notify_all();
479 PauseFetchFrame();
480 }
481
FetchFrameAtTime(int64_t timeUs,int32_t option,const OutputConfiguration & param)482 std::shared_ptr<AVSharedMemory> AVThumbnailGenerator::FetchFrameAtTime(int64_t timeUs, int32_t option,
483 const OutputConfiguration ¶m)
484 {
485 MEDIA_LOGI("Fetch frame 0x%{public}06" PRIXPTR " timeUs:%{public}" PRId64 ", option:%{public}d,"
486 "dstWidth:%{public}d, dstHeight:%{public}d, colorFormat:%{public}d",
487 FAKE_POINTER(this), timeUs, option, param.dstWidth, param.dstHeight,
488 static_cast<int32_t>(param.colorFormat));
489 CHECK_AND_RETURN_RET_LOG(mediaDemuxer_ != nullptr, nullptr, "FetchFrameAtTime demuxer is nullptr");
490
491 readErrorFlag_ = false;
492 hasFetchedFrame_ = false;
493 isBufferAvailable_ = false;
494 outputConfig_ = param;
495 seekTime_ = timeUs;
496 trackInfo_ = GetVideoTrackInfo();
497 CHECK_AND_RETURN_RET_LOG(trackInfo_ != nullptr, nullptr, "FetchFrameAtTime trackInfo_ is nullptr.");
498 mediaDemuxer_->Resume();
499 mediaDemuxer_->SelectTrack(trackIndex_);
500 int64_t realSeekTime = timeUs;
501 auto res = SeekToTime(Plugins::Us2Ms(timeUs), static_cast<Plugins::SeekMode>(option), realSeekTime);
502 CHECK_AND_RETURN_RET_LOG(res == Status::OK, nullptr, "Seek fail");
503 CHECK_AND_RETURN_RET_LOG(InitDecoder() == Status::OK, nullptr, "FetchFrameAtTime InitDecoder failed.");
504 bool fetchFrameRes = false;
505 {
506 std::unique_lock<std::mutex> lock(mutex_);
507
508 // wait up to 3s to fetch frame AVSharedMemory at time.
509 fetchFrameRes = cond_.wait_for(lock, std::chrono::seconds(MAX_WAIT_TIME_SECOND),
510 [this] { return hasFetchedFrame_.load() || readErrorFlag_.load() || stopProcessing_.load(); });
511 }
512 if (fetchFrameRes) {
513 HandleFetchFrameAtTimeRes();
514 } else {
515 PauseFetchFrame();
516 }
517 return fetchedFrameAtTime_;
518 }
519
HandleFetchFrameAtTimeRes()520 void AVThumbnailGenerator::HandleFetchFrameAtTimeRes()
521 {
522 CHECK_AND_RETURN_RET_LOG(!readErrorFlag_.load(), PauseFetchFrame(), "ReadSample error, exit fetchFrame");
523 CHECK_AND_RETURN_RET_LOG(!stopProcessing_.load(), PauseFetchFrame(), "Destroy or Decoder error, exit fetchFrame");
524 MEDIA_LOGI("0x%{public}06" PRIXPTR " Fetch frame OK width:%{public}d, height:%{public}d",
525 FAKE_POINTER(this), outputConfig_.dstWidth, outputConfig_.dstHeight);
526 ConvertToAVSharedMemory();
527 videoDecoder_->ReleaseOutputBuffer(bufferIndex_, false);
528 }
529
FetchFrameYuv(int64_t timeUs,int32_t option,const OutputConfiguration & param)530 std::shared_ptr<AVBuffer> AVThumbnailGenerator::FetchFrameYuv(int64_t timeUs, int32_t option,
531 const OutputConfiguration ¶m)
532 {
533 MEDIA_LOGI("Fetch frame 0x%{public}06" PRIXPTR " timeUs:%{public}" PRId64 ", option:%{public}d,"
534 "dstWidth:%{public}d, dstHeight:%{public}d, colorFormat:%{public}d",
535 FAKE_POINTER(this), timeUs, option, param.dstWidth, param.dstHeight,
536 static_cast<int32_t>(param.colorFormat));
537 CHECK_AND_RETURN_RET_LOG(mediaDemuxer_ != nullptr, nullptr, "FetchFrameAtTime demuxer is nullptr");
538 avBuffer_ = nullptr;
539 readErrorFlag_ = false;
540 hasFetchedFrame_ = false;
541 isBufferAvailable_ = false;
542 outputConfig_ = param;
543 seekTime_ = timeUs;
544 trackInfo_ = GetVideoTrackInfo();
545 CHECK_AND_RETURN_RET_LOG(trackInfo_ != nullptr, nullptr, "FetchFrameAtTime trackInfo_ is nullptr.");
546 mediaDemuxer_->SelectTrack(trackIndex_);
547 int64_t realSeekTime = timeUs;
548 auto res = SeekToTime(Plugins::Us2Ms(timeUs), static_cast<Plugins::SeekMode>(option), realSeekTime);
549 CHECK_AND_RETURN_RET_LOG(res == Status::OK, nullptr, "Seek fail");
550 CHECK_AND_RETURN_RET_LOG(InitDecoder() == Status::OK, nullptr, "FetchFrameAtTime InitDecoder failed.");
551 bool fetchFrameRes = false;
552 {
553 std::unique_lock<std::mutex> lock(mutex_);
554
555 // wait up to 3s to fetch frame AVSharedMemory at time.
556 fetchFrameRes = cond_.wait_for(lock, std::chrono::seconds(MAX_WAIT_TIME_SECOND),
557 [this] { return hasFetchedFrame_.load() || readErrorFlag_.load() || stopProcessing_.load(); });
558 }
559 if (fetchFrameRes) {
560 HandleFetchFrameYuvRes();
561 } else {
562 HandleFetchFrameYuvFailed();
563 }
564 return avBuffer_;
565 }
566
HandleFetchFrameYuvRes()567 void AVThumbnailGenerator::HandleFetchFrameYuvRes()
568 {
569 CHECK_AND_RETURN_RET_LOG(!readErrorFlag_.load(), HandleFetchFrameYuvFailed(), "ReadSample error, exit fetchFrame");
570 CHECK_AND_RETURN_RET_LOG(!stopProcessing_.load(), HandleFetchFrameYuvFailed(),
571 "Destroy or Decoder error, exit fetchFrame");
572 MEDIA_LOGI("0x%{public}06" PRIXPTR " Fetch frame OK width:%{public}d, height:%{public}d",
573 FAKE_POINTER(this), outputConfig_.dstWidth, outputConfig_.dstHeight);
574 avBuffer_ = GenerateAlignmentAvBuffer();
575 if (avBuffer_ != nullptr && avBuffer_->meta_ != nullptr) {
576 avBuffer_->meta_->Set<Tag::VIDEO_WIDTH>(width_);
577 avBuffer_->meta_->Set<Tag::VIDEO_HEIGHT>(height_);
578 avBuffer_->meta_->Set<Tag::VIDEO_ROTATION>(rotation_);
579 avBuffer_->meta_->Set<Tag::VIDEO_ORIENTATION_TYPE>(orientation_);
580 }
581 }
582
HandleFetchFrameYuvFailed()583 void AVThumbnailGenerator::HandleFetchFrameYuvFailed()
584 {
585 CHECK_AND_RETURN_LOG(videoDecoder_ != nullptr, "videoDecoder_ is nullptr");
586 videoDecoder_->ReleaseOutputBuffer(bufferIndex_, false);
587 PauseFetchFrame();
588 }
589
SeekToTime(int64_t timeMs,Plugins::SeekMode option,int64_t realSeekTime)590 Status AVThumbnailGenerator::SeekToTime(int64_t timeMs, Plugins::SeekMode option, int64_t realSeekTime)
591 {
592 seekMode_ = option;
593 if (option == Plugins::SeekMode::SEEK_CLOSEST) {
594 option = Plugins::SeekMode::SEEK_PREVIOUS_SYNC;
595 }
596 timeMs = duration_ > 0 ? std::min(timeMs, Plugins::Us2Ms(duration_)) : timeMs;
597 auto res = mediaDemuxer_->SeekTo(timeMs, option, realSeekTime);
598 if (res != Status::OK && option != Plugins::SeekMode::SEEK_CLOSEST_SYNC) {
599 res = mediaDemuxer_->SeekTo(timeMs, Plugins::SeekMode::SEEK_CLOSEST_SYNC, realSeekTime);
600 seekMode_ = Plugins::SeekMode::SEEK_CLOSEST_SYNC;
601 }
602 return res;
603 }
604
ConvertToAVSharedMemory()605 void AVThumbnailGenerator::ConvertToAVSharedMemory()
606 {
607 auto surfaceBuffer = avBuffer_->memory_->GetSurfaceBuffer();
608 if (surfaceBuffer != nullptr) {
609 auto ret = GetYuvDataAlignStride(surfaceBuffer);
610 CHECK_AND_RETURN_LOG(ret == MSERR_OK, "Copy frame failed");
611 OutputFrame *frame = reinterpret_cast<OutputFrame *>(fetchedFrameAtTime_->GetBase());
612 frame->width_ = surfaceBuffer->GetWidth();
613 frame->height_ = surfaceBuffer->GetHeight();
614 frame->stride_ = frame->width_ * RATE_UV;
615 frame->bytesPerPixel_ = RATE_UV;
616 frame->size_ = frame->width_ * frame->height_ * BYTES_PER_PIXEL_YUV;
617 frame->rotation_ = static_cast<int32_t>(rotation_);
618 return;
619 }
620
621 int32_t width;
622 int32_t height;
623 outputFormat_.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width);
624 outputFormat_.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
625 if (width == 0 || height == 0) {
626 width = width_;
627 height = height_;
628 }
629
630 fetchedFrameAtTime_ = std::make_shared<AVSharedMemoryBase>(sizeof(OutputFrame) + avBuffer_->memory_->GetSize(),
631 AVSharedMemory::Flags::FLAGS_READ_WRITE, "FetchedFrameMemory");
632 int32_t ret = fetchedFrameAtTime_->Init();
633 CHECK_AND_RETURN_LOG(ret == static_cast<int32_t>(Status::OK), "Create AVSharedmemory failed, ret:%{public}d", ret);
634 OutputFrame *frame = reinterpret_cast<OutputFrame *>(fetchedFrameAtTime_->GetBase());
635 frame->width_ = width;
636 frame->height_ = height;
637 frame->stride_ = width * RATE_UV;
638 frame->bytesPerPixel_ = RATE_UV;
639 frame->size_ = avBuffer_->memory_->GetSize();
640 frame->rotation_ = static_cast<int32_t>(rotation_);
641 fetchedFrameAtTime_->Write(avBuffer_->memory_->GetAddr(), frame->size_, sizeof(OutputFrame));
642 }
643
ConvertP010ToNV12(const sptr<SurfaceBuffer> & surfaceBuffer,uint8_t * dstNV12,int32_t strideWidth,int32_t strideHeight)644 void AVThumbnailGenerator::ConvertP010ToNV12(const sptr<SurfaceBuffer> &surfaceBuffer, uint8_t *dstNV12,
645 int32_t strideWidth, int32_t strideHeight)
646 {
647 int32_t width = surfaceBuffer->GetWidth();
648 int32_t height = surfaceBuffer->GetHeight();
649 uint8_t *srcP010 = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr());
650
651 // copy src Y component to dst
652 for (int32_t i = 0; i < height; i++) {
653 uint16_t *srcY = reinterpret_cast<uint16_t *>(srcP010 + strideWidth * i);
654 uint8_t *dstY = dstNV12 + width * i;
655 for (int32_t j = 0; j < width; j++) {
656 *dstY = static_cast<uint8_t>(*srcY >> SHIFT_BITS_P010_2_NV12);
657 srcY++;
658 dstY++;
659 }
660 }
661
662 uint8_t *maxDstAddr = dstNV12 + width * height + width * height / RATE_UV;
663 uint8_t *originSrcAddr = srcP010;
664 uint16_t *maxSrcAddr = reinterpret_cast<uint16_t *>(originSrcAddr) + surfaceBuffer->GetSize();
665
666 srcP010 = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr()) + strideWidth * strideHeight;
667 dstNV12 = dstNV12 + width * height;
668
669 // copy src UV component to dst, height(UV) = height(Y) / 2;
670 for (int32_t i = 0; i < height / 2; i++) {
671 uint16_t *srcUV = reinterpret_cast<uint16_t *>(srcP010 + strideWidth * i);
672 uint8_t *dstUV = dstNV12 + width * i;
673 for (int32_t j = 0; j < width && srcUV < maxSrcAddr && dstUV < maxDstAddr; j++) {
674 *dstUV = static_cast<uint8_t>(*srcUV >> SHIFT_BITS_P010_2_NV12);
675 *(dstUV + 1) = static_cast<uint8_t>(*(srcUV + 1) >> SHIFT_BITS_P010_2_NV12);
676 srcUV += 2; // srcUV move by 2 to process U and V component
677 dstUV += 2; // dstUV move by 2 to process U and V component
678 }
679 }
680 }
681
GenerateAlignmentAvBuffer()682 std::shared_ptr<AVBuffer> AVThumbnailGenerator::GenerateAlignmentAvBuffer()
683 {
684 CHECK_AND_RETURN_RET_LOG(avBuffer_ != nullptr && avBuffer_->memory_ != nullptr, nullptr,
685 "Generate Alignment AvBuffer failed, avBuffer_ or avBuffer_->memory_ is nullptr.");
686 if (avBuffer_->memory_->GetSize() != 0 && avBuffer_->memory_->GetSurfaceBuffer() == nullptr) {
687 return GenerateAvBufferFromFCodec();
688 }
689 CHECK_AND_RETURN_RET_LOG(avBuffer_->memory_->GetSurfaceBuffer() != nullptr, nullptr,
690 "Memory size is 0, SurfaceBuffer is nullptr.");
691 auto srcSurfaceBuffer = avBuffer_->memory_->GetSurfaceBuffer();
692 auto width = srcSurfaceBuffer->GetWidth();
693 auto height = srcSurfaceBuffer->GetHeight();
694 bool isHdr = srcSurfaceBuffer->GetFormat() ==
695 static_cast<int32_t>(GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_P010);
696
697 sptr<SurfaceBuffer> dstSurfaceBuffer = SurfaceBuffer::Create();
698 BufferRequestConfig requestConfig = {
699 .width = width,
700 .height = height,
701 .strideAlignment = 0x2,
702 .format = srcSurfaceBuffer->GetFormat(), // always yuv
703 .usage = srcSurfaceBuffer->GetUsage(),
704 .timeout = 0,
705 };
706 CHECK_AND_RETURN_RET_LOG(dstSurfaceBuffer != nullptr, nullptr, "Create surfaceBuffer failed");
707 GSError allocRes = dstSurfaceBuffer->Alloc(requestConfig);
708 CHECK_AND_RETURN_RET_LOG(allocRes == 0, nullptr, "Alloc surfaceBuffer failed, ecode %{public}d", allocRes);
709
710 CopySurfaceBufferInfo(srcSurfaceBuffer, dstSurfaceBuffer);
711 int32_t copyRes = memcpy_s(dstSurfaceBuffer->GetVirAddr(), dstSurfaceBuffer->GetSize(),
712 srcSurfaceBuffer->GetVirAddr(), srcSurfaceBuffer->GetSize());
713 CHECK_AND_RETURN_RET_LOG(copyRes == EOK, nullptr, "copy surface buffer pixels failed, copyRes %{public}d", copyRes);
714 int32_t outputHeight;
715 auto hasSliceHeight = outputFormat_.GetIntValue(Tag::VIDEO_SLICE_HEIGHT, outputHeight);
716 if (!hasSliceHeight || outputHeight < height) {
717 outputHeight = height;
718 }
719
720 // create avBuffer from surfaceBuffer
721 std::shared_ptr<AVBuffer> targetAvBuffer = AVBuffer::CreateAVBuffer(dstSurfaceBuffer);
722 bool ret = targetAvBuffer && targetAvBuffer->memory_ && targetAvBuffer->meta_ &&
723 targetAvBuffer->memory_->GetSurfaceBuffer() != nullptr;
724 CHECK_AND_RETURN_RET_LOG(ret, nullptr, "create avBuffer failed");
725 targetAvBuffer->meta_->Set<Tag::VIDEO_IS_HDR_VIVID>(isHdr);
726 targetAvBuffer->meta_->Set<Tag::VIDEO_SLICE_HEIGHT>(outputHeight);
727 targetAvBuffer->flag_ = avBuffer_->flag_;
728 return targetAvBuffer;
729 }
730
GenerateAvBufferFromFCodec()731 std::shared_ptr<AVBuffer> AVThumbnailGenerator::GenerateAvBufferFromFCodec()
732 {
733 AVBufferConfig avBufferConfig;
734 avBufferConfig.size = avBuffer_->memory_->GetSize();
735 avBufferConfig.memoryType = MemoryType::SHARED_MEMORY;
736 avBufferConfig.memoryFlag = MemoryFlag::MEMORY_READ_WRITE;
737 std::shared_ptr<AVBuffer> targetAvBuffer = AVBuffer::CreateAVBuffer(avBufferConfig);
738 CHECK_AND_RETURN_RET_LOG(targetAvBuffer != nullptr && targetAvBuffer->memory_ != nullptr, nullptr,
739 "Create avBuffer failed");
740 targetAvBuffer->memory_->Write(avBuffer_->memory_->GetAddr(), avBuffer_->memory_->GetSize(), 0);
741 return targetAvBuffer;
742 }
743
GetYuvDataAlignStride(const sptr<SurfaceBuffer> & surfaceBuffer)744 int32_t AVThumbnailGenerator::GetYuvDataAlignStride(const sptr<SurfaceBuffer> &surfaceBuffer)
745 {
746 int32_t width = surfaceBuffer->GetWidth();
747 int32_t height = surfaceBuffer->GetHeight();
748 int32_t stride = surfaceBuffer->GetStride();
749 int32_t outputHeight;
750 auto hasSliceHeight = outputFormat_.GetIntValue(Tag::VIDEO_SLICE_HEIGHT, outputHeight);
751 if (!hasSliceHeight || outputHeight < height) {
752 outputHeight = height;
753 }
754 MEDIA_LOGD("GetYuvDataAlignStride stride:%{public}d, strideWidth:%{public}d, outputHeight:%{public}d", stride,
755 stride, outputHeight);
756
757 fetchedFrameAtTime_ =
758 std::make_shared<AVSharedMemoryBase>(sizeof(OutputFrame) + width * height * BYTES_PER_PIXEL_YUV,
759 AVSharedMemory::Flags::FLAGS_READ_WRITE, "FetchedFrameMemory");
760 auto ret = fetchedFrameAtTime_->Init();
761 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Create AVSharedmemory failed, ret:%{public}d", ret);
762 uint8_t *dstPtr = static_cast<uint8_t *>(sizeof(OutputFrame) + fetchedFrameAtTime_->GetBase());
763 uint8_t *srcPtr = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr());
764 int32_t format = surfaceBuffer->GetFormat();
765 if (format == static_cast<int32_t>(GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_P010)) {
766 ConvertP010ToNV12(surfaceBuffer, dstPtr, stride, outputHeight);
767 return MSERR_OK;
768 }
769
770 // copy src Y component to dst
771 for (int32_t y = 0; y < height; y++) {
772 auto ret = memcpy_s(dstPtr, width, srcPtr, width);
773 if (ret != EOK) {
774 MEDIA_LOGW("Memcpy Y component failed.");
775 }
776 srcPtr += stride;
777 dstPtr += width;
778 }
779
780 srcPtr = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr()) + stride * outputHeight;
781
782 // copy src UV component to dst, height(UV) = height(Y) / 2
783 for (int32_t uv = 0; uv < height / 2; uv++) {
784 auto ret = memcpy_s(dstPtr, width, srcPtr, width);
785 if (ret != EOK) {
786 MEDIA_LOGW("Memcpy UV component failed.");
787 }
788 srcPtr += stride;
789 dstPtr += width;
790 }
791 return MSERR_OK;
792 }
793
Reset()794 void AVThumbnailGenerator::Reset()
795 {
796 if (mediaDemuxer_ != nullptr) {
797 mediaDemuxer_->Reset();
798 }
799
800 if (videoDecoder_ != nullptr) {
801 videoDecoder_->Reset();
802 }
803
804 FlushBufferQueue();
805
806 hasFetchedFrame_ = false;
807 fileType_ = FileType::UNKNOW;
808 trackInfo_ = nullptr;
809 }
810
FlushBufferQueue()811 void AVThumbnailGenerator::FlushBufferQueue()
812 {
813 {
814 std::unique_lock<std::mutex> lock(queueMutex_);
815 if (inputBufferQueueConsumer_ != nullptr) {
816 for (auto &buffer : bufferVector_) {
817 inputBufferQueueConsumer_->DetachBuffer(buffer);
818 }
819 bufferVector_.clear();
820 inputBufferQueueConsumer_->SetQueueSize(0);
821 }
822 isBufferAvailable_ = false;
823 }
824 {
825 std::unique_lock<std::mutex> lock(dtsQueMutex_);
826 if (!inputBufferDtsQue_.empty()) {
827 MEDIA_LOGI("Clear dtsQue_, currrent size: %{public}" PRIu64,
828 static_cast<uint64_t>(inputBufferDtsQue_.size()));
829 inputBufferDtsQue_.clear();
830 }
831 }
832 }
833
CopySurfaceBufferInfo(sptr<SurfaceBuffer> & source,sptr<SurfaceBuffer> & dst)834 void AVThumbnailGenerator::CopySurfaceBufferInfo(sptr<SurfaceBuffer> &source, sptr<SurfaceBuffer> &dst)
835 {
836 if (source == nullptr || dst == nullptr) {
837 MEDIA_LOGI("CopySurfaceBufferInfo failed, source or dst is nullptr");
838 return;
839 }
840 std::vector<uint8_t> hdrMetadataTypeVec;
841 std::vector<uint8_t> colorSpaceInfoVec;
842 std::vector<uint8_t> staticData;
843 std::vector<uint8_t> dynamicData;
844
845 if (source->GetMetadata(ATTRKEY_HDR_METADATA_TYPE, hdrMetadataTypeVec) == GSERROR_OK) {
846 dst->SetMetadata(ATTRKEY_HDR_METADATA_TYPE, hdrMetadataTypeVec);
847 }
848 if (source->GetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoVec) == GSERROR_OK) {
849 dst->SetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoVec);
850 }
851 if (GetSbStaticMetadata(source, staticData) && (staticData.size() > 0)) {
852 SetSbStaticMetadata(dst, staticData);
853 }
854 if (GetSbDynamicMetadata(source, dynamicData) && (dynamicData.size()) > 0) {
855 SetSbDynamicMetadata(dst, dynamicData);
856 }
857 }
858
GetSbStaticMetadata(const sptr<SurfaceBuffer> & buffer,std::vector<uint8_t> & staticMetadata)859 bool AVThumbnailGenerator::GetSbStaticMetadata(const sptr<SurfaceBuffer> &buffer, std::vector<uint8_t> &staticMetadata)
860 {
861 return buffer->GetMetadata(ATTRKEY_HDR_STATIC_METADATA, staticMetadata) == GSERROR_OK;
862 }
863
GetSbDynamicMetadata(const sptr<SurfaceBuffer> & buffer,std::vector<uint8_t> & dynamicMetadata)864 bool AVThumbnailGenerator::GetSbDynamicMetadata(const sptr<SurfaceBuffer> &buffer,
865 std::vector<uint8_t> &dynamicMetadata)
866 {
867 return buffer->GetMetadata(ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata) == GSERROR_OK;
868 }
869
SetSbStaticMetadata(sptr<SurfaceBuffer> & buffer,const std::vector<uint8_t> & staticMetadata)870 bool AVThumbnailGenerator::SetSbStaticMetadata(sptr<SurfaceBuffer> &buffer, const std::vector<uint8_t> &staticMetadata)
871 {
872 return buffer->SetMetadata(ATTRKEY_HDR_STATIC_METADATA, staticMetadata) == GSERROR_OK;
873 }
874
SetSbDynamicMetadata(sptr<SurfaceBuffer> & buffer,const std::vector<uint8_t> & dynamicMetadata)875 bool AVThumbnailGenerator::SetSbDynamicMetadata(sptr<SurfaceBuffer> &buffer,
876 const std::vector<uint8_t> &dynamicMetadata)
877 {
878 return buffer->SetMetadata(ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata) == GSERROR_OK;
879 }
880
Destroy()881 void AVThumbnailGenerator::Destroy()
882 {
883 {
884 std::unique_lock<std::mutex> lock(queueMutex_);
885 stopProcessing_ = true;
886 }
887 bufferAvailableCond_.notify_all();
888
889 if (readTask_ != nullptr) {
890 readTask_->Stop();
891 }
892
893 if (videoDecoder_ != nullptr) {
894 videoDecoder_->Stop();
895 videoDecoder_->Release();
896 }
897 mediaDemuxer_ = nullptr;
898 videoDecoder_ = nullptr;
899 MEDIA_LOGI("0x%{public}06" PRIXPTR " Finish Destroy.", FAKE_POINTER(this));
900 }
901
PauseFetchFrame()902 void AVThumbnailGenerator::PauseFetchFrame()
903 {
904 hasFetchedFrame_ = true;
905 mediaDemuxer_->Pause();
906 mediaDemuxer_->Flush();
907 videoDecoder_->Flush();
908 Format format;
909 format.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, frameRate_);
910 videoDecoder_->SetParameter(format);
911 FlushBufferQueue();
912 }
913 } // namespace Media
914 } // namespace OHOS