1 /*
2 * Copyright (c) 2021-2021 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 #define HST_LOG_TAG "FFMpeg_Muxer"
17
18 #include "ffmpeg_muxer_plugin.h"
19
20 #include <functional>
21 #include <set>
22
23 #include "foundation/log.h"
24 #include "foundation/osal/thread/scoped_lock.h"
25 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
26 #include "plugins/ffmpeg_adapter/utils/ffmpeg_codec_map.h"
27
28 namespace {
29 using namespace OHOS::Media::Plugin;
30 using namespace Ffmpeg;
31
__anon5765b3620202(uint32_t i) 32 std::function<int32_t(uint32_t)> ui2iFunc = [](uint32_t i) {return i;};
33
34 std::map<std::string, std::shared_ptr<AVOutputFormat>> g_pluginOutputFmt;
35
36 std::set<std::string> g_supportedMuxer = {"mp4", "h264"};
37
IsMuxerSupported(const char * name)38 bool IsMuxerSupported(const char* name)
39 {
40 return g_supportedMuxer.count(name) == 1;
41 }
42
UpdatePluginInCapability(AVCodecID codecId,CapabilitySet & capSet)43 bool UpdatePluginInCapability(AVCodecID codecId, CapabilitySet& capSet)
44 {
45 if (codecId != AV_CODEC_ID_NONE) {
46 Capability cap;
47 if (!FFCodecMap::CodecId2Cap(codecId, true, cap)) {
48 return false;
49 } else {
50 capSet.emplace_back(cap);
51 }
52 }
53 return true;
54 }
55
UpdatePluginCapability(const AVOutputFormat * oFmt,MuxerPluginDef & pluginDef)56 bool UpdatePluginCapability(const AVOutputFormat* oFmt, MuxerPluginDef& pluginDef)
57 {
58 if (!FFCodecMap::FormatName2Cap(oFmt->name, pluginDef.outCaps)) {
59 MEDIA_LOG_D(PUBLIC_LOG_S " is not supported now", oFmt->name);
60 return false;
61 }
62 UpdatePluginInCapability(oFmt->audio_codec, pluginDef.inCaps);
63 UpdatePluginInCapability(oFmt->video_codec, pluginDef.inCaps);
64 UpdatePluginInCapability(oFmt->subtitle_codec, pluginDef.inCaps);
65 return true;
66 }
67
RegisterMuxerPlugins(const std::shared_ptr<Register> & reg)68 Status RegisterMuxerPlugins(const std::shared_ptr<Register>& reg)
69 {
70 MEDIA_LOG_D("register muxer plugins.");
71 FALSE_RETURN_V_MSG_E(reg != nullptr, Status::ERROR_INVALID_PARAMETER,
72 "RegisterPlugins failed due to null pointer for reg.");
73 const AVOutputFormat* outputFormat = nullptr;
74 void* ite = nullptr;
75 while ((outputFormat = av_muxer_iterate(&ite))) {
76 MEDIA_LOG_DD("check ffmpeg muxer name: " PUBLIC_LOG_S, outputFormat->name);
77 if (!IsMuxerSupported(outputFormat->name)) {
78 continue;
79 }
80 if (outputFormat->long_name != nullptr) {
81 if (!strncmp(outputFormat->long_name, "raw ", 4)) { // 4
82 continue;
83 }
84 }
85 std::string pluginName = "ffmpegMux_" + std::string(outputFormat->name);
86 ReplaceDelimiter(".,|-<> ", '_', pluginName);
87 MuxerPluginDef def;
88 if (!UpdatePluginCapability(outputFormat, def)) {
89 continue;
90 }
91 def.name = pluginName;
92 def.description = "ffmpeg muxer";
93 def.rank = 100; // 100
94 def.creator = [](const std::string& name) -> std::shared_ptr<MuxerPlugin> {
95 return std::make_shared<FFmpegMuxerPlugin>(name);
96 };
97 if (reg->AddPlugin(def) != Status::OK) {
98 MEDIA_LOG_W("fail to add plugin " PUBLIC_LOG_S, pluginName.c_str());
99 continue;
100 }
101 g_pluginOutputFmt[pluginName] = std::shared_ptr<AVOutputFormat>(const_cast<AVOutputFormat*>(outputFormat),
102 [](AVOutputFormat* ptr) {}); // do not delete
103 }
104 return Status::OK;
105 }
__anon5765b3620502null106 PLUGIN_DEFINITION(FFmpegMuxers, LicenseType::LGPL, RegisterMuxerPlugins, [] {g_pluginOutputFmt.clear();})
107
108 Status SetCodecByMime(const AVOutputFormat* fmt, const std::string& mime, AVStream* stream)
109 {
110 AVCodecID id = AV_CODEC_ID_NONE;
111 FALSE_RETURN_V_MSG_E(FFCodecMap::Mime2CodecId(mime, id), Status::ERROR_UNSUPPORTED_FORMAT,
112 "mime " PUBLIC_LOG_S " has no corresponding codec id", mime.c_str());
113 auto ptr = avcodec_find_encoder(id);
114 FALSE_RETURN_V_MSG_E(ptr != nullptr, Status::ERROR_UNSUPPORTED_FORMAT,
115 "codec of mime " PUBLIC_LOG_S " is not founder as encoder", mime.c_str());
116 bool matched = true;
117 switch (ptr->type) {
118 case AVMEDIA_TYPE_VIDEO:
119 matched = id == fmt->video_codec;
120 break;
121 case AVMEDIA_TYPE_AUDIO:
122 matched = id == fmt->audio_codec;
123 break;
124 case AVMEDIA_TYPE_SUBTITLE:
125 matched = id == fmt->subtitle_codec;
126 break;
127 default:
128 matched = false;
129 }
130 FALSE_RETURN_V_MSG_E(matched, Status::ERROR_UNSUPPORTED_FORMAT, "codec of mime " PUBLIC_LOG_S
131 " is not matched with " PUBLIC_LOG_S " muxer", mime.c_str(), fmt->name);
132 stream->codecpar->codec_id = id;
133 stream->codecpar->codec_type = ptr->type;
134 return Status::OK;
135 }
136
SetCodecOfTrack(const AVOutputFormat * fmt,AVStream * stream,const Meta & meta)137 Status SetCodecOfTrack(const AVOutputFormat* fmt, AVStream* stream, const Meta& meta)
138 {
139 std::string mime;
140 FALSE_RETURN_V(meta.Get<Tag::MIME>(mime), Status::ERROR_INVALID_PARAMETER);
141 // todo specially for audio/mpeg audio/mpeg we should check mpegversion and mpeglayer
142
143 return SetCodecByMime(fmt, AnyCast<std::string>(mime), stream);
144 }
145
SetParameterOfAuTrack(AVStream * stream,const Meta & meta)146 Status SetParameterOfAuTrack(AVStream* stream, const Meta& meta)
147 {
148 uint32_t channels;
149 uint32_t sampleRate;
150 uint32_t perFrame;
151 AudioSampleFormat sampleFormat;
152 AudioChannelLayout layout;
153
154 FALSE_RETURN_V(meta.Get<Tag::AUDIO_SAMPLE_FORMAT>(sampleFormat),
155 Status::ERROR_INVALID_PARAMETER);
156 stream->codecpar->format = static_cast<int>(ConvP2FfSampleFmt(sampleFormat));
157
158 FALSE_RETURN_V(meta.Get<Tag::AUDIO_CHANNELS>(channels),
159 Status::ERROR_INVALID_PARAMETER);
160 stream->codecpar->channels = ui2iFunc(channels);
161
162 FALSE_RETURN_V(meta.Get<Tag::AUDIO_SAMPLE_RATE>(sampleRate),
163 Status::ERROR_INVALID_PARAMETER);
164 stream->codecpar->sample_rate = ui2iFunc(sampleRate);
165
166 FALSE_RETURN_V(meta.Get<Tag::AUDIO_SAMPLE_PER_FRAME>(perFrame),
167 Status::ERROR_INVALID_PARAMETER);
168 stream->codecpar->frame_size = ui2iFunc(perFrame);
169
170 FALSE_RETURN_V(meta.Get<Tag::AUDIO_CHANNEL_LAYOUT>(layout),
171 Status::ERROR_INVALID_PARAMETER);
172 stream->codecpar->channel_layout = (uint64_t)layout;
173 return Status::OK;
174 }
175
SetParameterOfVdTrack(AVStream * stream,const Meta & meta)176 Status SetParameterOfVdTrack(AVStream* stream, const Meta& meta)
177 {
178 uint32_t width;
179 uint32_t height;
180 uint32_t level;
181 int64_t bitRate;
182 VideoPixelFormat format;
183 VideoH264Profile profile;
184 FALSE_RETURN_V(meta.Get<Tag::VIDEO_PIXEL_FORMAT>(format),
185 Status::ERROR_INVALID_PARAMETER);
186 stream->codecpar->format = static_cast<int>(ConvertPixelFormatToFFmpeg(format));
187
188 FALSE_RETURN_V(meta.Get<Tag::VIDEO_WIDTH>(width),
189 Status::ERROR_INVALID_PARAMETER);
190 stream->codecpar->width = ui2iFunc(width);
191
192 FALSE_RETURN_V(meta.Get<Tag::VIDEO_HEIGHT>(height),
193 Status::ERROR_INVALID_PARAMETER);
194 stream->codecpar->height = ui2iFunc(height);
195
196 FALSE_RETURN_V(meta.Get<Tag::MEDIA_BITRATE>(bitRate),
197 Status::ERROR_INVALID_PARAMETER);
198 stream->codecpar->bit_rate = bitRate;
199
200 FALSE_RETURN_V(meta.Get<Tag::VIDEO_H264_PROFILE>(profile),
201 Status::ERROR_INVALID_PARAMETER);
202 stream->codecpar->profile = static_cast<int>(ConvH264ProfileToFfmpeg(profile));
203
204 FALSE_RETURN_V(meta.Get<Tag::VIDEO_H264_LEVEL>(level),
205 Status::ERROR_INVALID_PARAMETER);
206 stream->codecpar->level = ui2iFunc(level);
207 return Status::OK;
208 }
209
SetParameterOfSubTitleTrack(AVStream * stream,const Meta & meta)210 Status SetParameterOfSubTitleTrack(AVStream* stream, const Meta& meta)
211 {
212 // todo add subtitle
213 MEDIA_LOG_E("should add subtitle tack parameter setter");
214 return Status::ERROR_UNKNOWN;
215 }
216
ResetCodecParameter(AVCodecParameters * par)217 void ResetCodecParameter(AVCodecParameters* par)
218 {
219 av_freep(&par->extradata);
220 (void)memset_s(par, sizeof(*par), 0, sizeof(*par));
221 par->codec_type = AVMEDIA_TYPE_UNKNOWN;
222 par->codec_id = AV_CODEC_ID_NONE;
223 par->format = -1;
224 par->profile = FF_PROFILE_UNKNOWN;
225 par->level = FF_LEVEL_UNKNOWN;
226 par->field_order = AV_FIELD_UNKNOWN;
227 par->color_range = AVCOL_RANGE_UNSPECIFIED;
228 par->color_primaries = AVCOL_PRI_UNSPECIFIED;
229 par->color_trc = AVCOL_TRC_UNSPECIFIED;
230 par->color_space = AVCOL_SPC_UNSPECIFIED;
231 par->chroma_location = AVCHROMA_LOC_UNSPECIFIED;
232 par->sample_aspect_ratio = AVRational {0, 1};
233 }
234
SetTagsOfTrack(const AVOutputFormat * fmt,AVStream * stream,const Meta & meta)235 Status SetTagsOfTrack(const AVOutputFormat* fmt, AVStream* stream, const Meta& meta)
236 {
237 FALSE_RETURN_V(stream != nullptr, Status::ERROR_INVALID_PARAMETER);
238 ResetCodecParameter(stream->codecpar);
239 // firstly mime
240 auto ret = SetCodecOfTrack(fmt, stream, meta);
241 NOK_RETURN(ret);
242 if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // audio
243 ret = SetParameterOfAuTrack(stream, meta);
244 } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // video
245 ret = SetParameterOfVdTrack(stream, meta);
246 } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { // subtitle
247 ret = SetParameterOfSubTitleTrack(stream, meta);
248 } else {
249 MEDIA_LOG_W("unknown codec type of stream " PUBLIC_LOG_D32, stream->index);
250 }
251 NOK_RETURN(ret);
252 // others
253
254 FALSE_RETURN_V(meta.Get<Tag::MEDIA_BITRATE>(stream->codecpar->bit_rate),
255 Status::ERROR_INVALID_PARAMETER);
256 // extra data
257 CodecConfig codecConfig;
258 FALSE_RETURN_V(meta.Get<Tag::MEDIA_CODEC_CONFIG>(codecConfig),
259 Status::ERROR_INVALID_PARAMETER);
260 if (!codecConfig.empty()) {
261 auto extraSize = codecConfig.size();
262 stream->codecpar->extradata = static_cast<uint8_t *>(av_mallocz(extraSize + AV_INPUT_BUFFER_PADDING_SIZE));
263 FALSE_RETURN_V(stream->codecpar->extradata != nullptr, Status::ERROR_NO_MEMORY);
264 auto ret = memcpy_s(stream->codecpar->extradata, extraSize, codecConfig.data(), extraSize);
265 FALSE_RETURN_V(ret == 0, Status::ERROR_UNKNOWN);
266 stream->codecpar->extradata_size = static_cast<int64_t>(extraSize);
267 }
268 return Status::OK;
269 }
270
SetTagsOfGeneral(AVFormatContext * fmtCtx,const Meta & tags)271 Status SetTagsOfGeneral(AVFormatContext* fmtCtx, const Meta& tags)
272 {
273 for (const auto& pair: tags) {
274 std::string metaName;
275 if (!FindAvMetaNameByTag(pair.first, metaName)) {
276 MEDIA_LOG_I("tag " PUBLIC_LOG_U32 " will not written as general meta", pair.first);
277 continue;
278 }
279 if (!Any::IsSameTypeWith<std::string>(pair.second)) {
280 continue;
281 }
282 auto value = AnyCast<std::string>(pair.second);
283 av_dict_set(&fmtCtx->metadata, metaName.c_str(), value.c_str(), 0);
284 }
285 return Status::OK;
286 }
287 }
288
289 namespace OHOS {
290 namespace Media {
291 namespace Plugin {
292 namespace Ffmpeg {
FFmpegMuxerPlugin(std::string name)293 FFmpegMuxerPlugin::FFmpegMuxerPlugin(std::string name) : MuxerPlugin(std::move(name)) {}
294
~FFmpegMuxerPlugin()295 FFmpegMuxerPlugin::~FFmpegMuxerPlugin()
296 {
297 Release();
298 }
Release()299 Status FFmpegMuxerPlugin::Release()
300 {
301 outputFormat_.reset();
302 cachePacket_.reset();
303 formatContext_.reset();
304 return Status::OK;
305 }
306
InitFormatCtxLocked()307 Status FFmpegMuxerPlugin::InitFormatCtxLocked()
308 {
309 if (formatContext_ == nullptr) {
310 auto ioCtx = InitAvIoCtx();
311 FALSE_RETURN_V(ioCtx != nullptr, Status::ERROR_NO_MEMORY);
312 auto fmt = avformat_alloc_context();
313 FALSE_RETURN_V(fmt != nullptr, Status::ERROR_NO_MEMORY);
314 fmt->pb = ioCtx;
315 fmt->oformat = outputFormat_.get();
316 fmt->flags = static_cast<uint32_t>(fmt->flags) | static_cast<uint32_t>(AVFMT_FLAG_CUSTOM_IO);
317 formatContext_ = std::shared_ptr<AVFormatContext>(fmt, [](AVFormatContext* ptr) {
318 if (ptr) {
319 DeInitAvIoCtx(ptr->pb);
320 avformat_free_context(ptr);
321 }
322 });
323 }
324 return Status::OK;
325 }
326
Init()327 Status FFmpegMuxerPlugin::Init()
328 {
329 MEDIA_LOG_D("Init entered.");
330 FALSE_RETURN_V(g_pluginOutputFmt.count(pluginName_) != 0, Status::ERROR_UNSUPPORTED_FORMAT);
331 outputFormat_ = g_pluginOutputFmt[pluginName_];
332 auto pkt = av_packet_alloc();
333 cachePacket_ = std::shared_ptr<AVPacket> (pkt, [] (AVPacket* packet) {av_packet_free(&packet);});
334 OSAL::ScopedLock lock(fmtMutex_);
335 return InitFormatCtxLocked();
336 }
337
Deinit()338 Status FFmpegMuxerPlugin::Deinit()
339 {
340 return Release();
341 }
342
InitAvIoCtx()343 AVIOContext* FFmpegMuxerPlugin::InitAvIoCtx()
344 {
345 constexpr int bufferSize = 4096; // 4096
346 auto buffer = static_cast<unsigned char*>(av_malloc(bufferSize));
347 FALSE_RETURN_V_MSG_E(buffer != nullptr, nullptr, "AllocAVIOContext failed to av_malloc...");
348 AVIOContext* avioContext = avio_alloc_context(buffer, bufferSize, AVIO_FLAG_WRITE, static_cast<void*>(&ioContext_),
349 IoRead, IoWrite, IoSeek);
350 if (avioContext == nullptr) {
351 MEDIA_LOG_E("AllocAVIOContext failed to avio_alloc_context...");
352 av_free(buffer);
353 return nullptr;
354 }
355 avioContext->seekable = AVIO_SEEKABLE_NORMAL;
356 return avioContext;
357 }
358
DeInitAvIoCtx(AVIOContext * ptr)359 void FFmpegMuxerPlugin::DeInitAvIoCtx(AVIOContext* ptr)
360 {
361 if (ptr != nullptr) {
362 ptr->opaque = nullptr;
363 av_freep(&ptr->buffer);
364 avio_context_free(&ptr);
365 }
366 }
367
Prepare()368 Status FFmpegMuxerPlugin::Prepare()
369 {
370 for (const auto& pair: trackParameters_) {
371 SetTagsOfTrack(outputFormat_.get(), formatContext_->streams[pair.first], pair.second);
372 }
373 SetTagsOfGeneral(formatContext_.get(), generalParameters_);
374 formatContext_->flags |= AVFMT_TS_NONSTRICT;
375 return Status::OK;
376 }
ResetIoCtx(IOContext & ioContext)377 void FFmpegMuxerPlugin::ResetIoCtx(IOContext& ioContext)
378 {
379 ioContext.dataSink_.reset();
380 ioContext.pos_ = 0;
381 ioContext.end_ = 0;
382 }
Reset()383 Status FFmpegMuxerPlugin::Reset()
384 {
385 ResetIoCtx(ioContext_);
386 generalParameters_.Clear();
387 trackParameters_.clear();
388 OSAL::ScopedLock lock(fmtMutex_);
389 if (outputFormat_->deinit) {
390 outputFormat_->deinit(formatContext_.get());
391 }
392 formatContext_.reset();
393 return InitFormatCtxLocked();
394 }
395
GetParameter(Tag tag,ValueType & value)396 Status FFmpegMuxerPlugin::GetParameter(Tag tag, ValueType& value)
397 {
398 return PluginBase::GetParameter(tag, value);
399 }
400
GetTrackParameter(uint32_t trackId,Tag tag,Plugin::ValueType & value)401 Status FFmpegMuxerPlugin::GetTrackParameter(uint32_t trackId, Tag tag, Plugin::ValueType& value)
402 {
403 return Status::ERROR_UNIMPLEMENTED;
404 }
405
SetParameter(Tag tag,const ValueType & value)406 Status FFmpegMuxerPlugin::SetParameter(Tag tag, const ValueType& value)
407 {
408 generalParameters_[tag] = value;
409 return Status::OK;
410 }
411
SetTrackParameter(uint32_t trackId,Tag tag,const Plugin::ValueType & value)412 Status FFmpegMuxerPlugin::SetTrackParameter(uint32_t trackId, Tag tag, const Plugin::ValueType& value)
413 {
414 FALSE_RETURN_V(trackId < formatContext_->nb_streams, Status::ERROR_INVALID_PARAMETER);
415 if (trackParameters_.count(trackId) == 0) {
416 trackParameters_.insert({trackId, Plugin::Meta()});
417 }
418 trackParameters_[trackId][tag] = value;
419 return Status::OK;
420 }
421
AddTrack(uint32_t & trackId)422 Status FFmpegMuxerPlugin::AddTrack(uint32_t &trackId)
423 {
424 OSAL::ScopedLock lock(fmtMutex_);
425 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_WRONG_STATE, "formatContext_ is NULL");
426 auto st = avformat_new_stream(formatContext_.get(), nullptr);
427 FALSE_RETURN_V_MSG_E(st != nullptr, Status::ERROR_NO_MEMORY, "avformat_new_stream fail");
428 st->codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN;
429 st->codecpar->codec_id = AV_CODEC_ID_NONE;
430 trackId = static_cast<uint32_t>(st->index);
431 return Status::OK;
432 }
433
SetDataSink(const std::shared_ptr<DataSink> & dataSink)434 Status FFmpegMuxerPlugin::SetDataSink(const std::shared_ptr<DataSink>& dataSink)
435 {
436 ioContext_.dataSink_ = dataSink;
437 return Status::OK;
438 }
439
WriteHeader()440 Status FFmpegMuxerPlugin::WriteHeader()
441 {
442 FALSE_RETURN_V(ioContext_.dataSink_ != nullptr && outputFormat_ != nullptr, Status::ERROR_WRONG_STATE);
443 OSAL::ScopedLock lock(fmtMutex_);
444 FALSE_RETURN_V(formatContext_ != nullptr, Status::ERROR_WRONG_STATE);
445 int ret = avformat_write_header(formatContext_.get(), nullptr);
446 FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_UNKNOWN, "failed to write header " PUBLIC_LOG_S,
447 AVStrError(ret).c_str());
448 return Status::OK;
449 }
450
WriteFrame(const std::shared_ptr<Plugin::Buffer> & buffer)451 Status FFmpegMuxerPlugin::WriteFrame(const std::shared_ptr<Plugin::Buffer>& buffer)
452 {
453 FALSE_RETURN_V(buffer != nullptr && !buffer->IsEmpty(), Status::ERROR_INVALID_PARAMETER);
454 uint32_t trackId = buffer->trackID;
455 FALSE_RETURN_V(trackId < formatContext_->nb_streams, Status::ERROR_INVALID_PARAMETER);
456 (void)memset_s(cachePacket_.get(), sizeof(AVPacket), 0, sizeof(AVPacket));
457 auto memory = buffer->GetMemory();
458 if (memory == nullptr) {
459 MEDIA_LOG_E("Get memory failed: nullptr");
460 return Status::ERROR_UNKNOWN;
461 }
462 cachePacket_->data = const_cast<uint8_t*>(memory->GetReadOnlyData());
463 cachePacket_->size = memory->GetSize();
464 cachePacket_->stream_index = static_cast<int>(trackId);
465 cachePacket_->pts = ConvertTimeToFFmpeg(buffer->pts, formatContext_->streams[trackId]->time_base);
466 cachePacket_->dts = cachePacket_->pts;
467 cachePacket_->flags = 0;
468 if (buffer->flag & BUFFER_FLAG_KEY_FRAME) {
469 MEDIA_LOG_D("It is key frame");
470 cachePacket_->flags |= AV_PKT_FLAG_KEY;
471 }
472 cachePacket_->duration = ConvertTimeToFFmpeg(buffer->duration, formatContext_->streams[trackId]->time_base);
473 auto ret = av_write_frame(formatContext_.get(), cachePacket_.get());
474 if (ret < 0) {
475 MEDIA_LOG_D("failed to write frame " PUBLIC_LOG_S, AVStrError(ret).c_str());
476 av_packet_unref(cachePacket_.get());
477 return Status::ERROR_UNKNOWN;
478 }
479 av_packet_unref(cachePacket_.get());
480 return Status::OK;
481 }
482
WriteTrailer()483 Status FFmpegMuxerPlugin::WriteTrailer()
484 {
485 FALSE_RETURN_V(ioContext_.dataSink_ != nullptr && outputFormat_ != nullptr, Status::ERROR_WRONG_STATE);
486 OSAL::ScopedLock lock(fmtMutex_);
487 FALSE_RETURN_V(formatContext_ != nullptr, Status::ERROR_WRONG_STATE);
488 av_write_frame(formatContext_.get(), nullptr); // flush out cache data
489 int ret = av_write_trailer(formatContext_.get());
490 if (ret != 0) {
491 MEDIA_LOG_E("failed to write trailer " PUBLIC_LOG_S, AVStrError(ret).c_str());
492 }
493 avio_flush(formatContext_->pb);
494 return Status::OK;
495 }
496
SetCallback(Callback * cb)497 Status FFmpegMuxerPlugin::SetCallback(Callback* cb)
498 {
499 return Status::END_OF_STREAM;
500 }
501
GetAllocator()502 std::shared_ptr<Allocator> FFmpegMuxerPlugin::GetAllocator()
503 {
504 return {};
505 }
506
IoRead(void * opaque,uint8_t * buf,int bufSize)507 int32_t FFmpegMuxerPlugin::IoRead(void* opaque, uint8_t* buf, int bufSize)
508 {
509 (void)opaque;
510 (void)buf;
511 (void)bufSize;
512 return 0;
513 }
IoWrite(void * opaque,uint8_t * buf,int bufSize)514 int32_t FFmpegMuxerPlugin::IoWrite(void* opaque, uint8_t* buf, int bufSize)
515 {
516 auto ioCtx = static_cast<IOContext*>(opaque);
517 if (ioCtx && ioCtx->dataSink_) {
518 auto buffer = std::make_shared<Buffer>();
519 auto bufferMem = buffer->AllocMemory(nullptr, bufSize);
520 if (bufferMem == nullptr) {
521 MEDIA_LOG_E("IoWrite buffer AllocMemory nullptr");
522 return -1;
523 }
524 auto bufferGetMem = buffer->GetMemory();
525 if (bufferGetMem == nullptr) {
526 MEDIA_LOG_E("IoWrite buffer GetMemory nullptr");
527 return -1;
528 }
529 bufferGetMem->Write(buf, bufSize, 0); // copy to buffer
530 auto res = ioCtx->dataSink_->WriteAt(ioCtx->pos_, buffer);
531 if (res == Status::OK) {
532 ioCtx->pos_ += bufferMem->GetSize();
533 if (ioCtx->pos_ > ioCtx->end_) {
534 ioCtx->end_ = ioCtx->pos_;
535 }
536 return bufferMem->GetSize();
537 }
538 return 0;
539 }
540 return -1;
541 }
542
IoSeek(void * opaque,int64_t offset,int whence)543 int64_t FFmpegMuxerPlugin::IoSeek(void* opaque, int64_t offset, int whence)
544 {
545 auto ioContext = static_cast<IOContext*>(opaque);
546 uint64_t newPos = 0;
547 switch (whence) {
548 case SEEK_SET:
549 newPos = static_cast<uint64_t>(offset);
550 ioContext->pos_ = newPos;
551 MEDIA_LOG_I("AVSeek whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG_U64,
552 whence, offset, newPos);
553 break;
554 case SEEK_CUR:
555 newPos = ioContext->pos_ + offset;
556 MEDIA_LOG_I("AVSeek whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG_U64,
557 whence, offset, newPos);
558 break;
559 case SEEK_END:
560 case AVSEEK_SIZE:
561 newPos = ioContext->end_ + offset;
562 MEDIA_LOG_I("AVSeek seek end whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64, whence, offset);
563 break;
564 default:
565 MEDIA_LOG_E("AVSeek unexpected whence: " PUBLIC_LOG_D32, whence);
566 break;
567 }
568 if (whence != AVSEEK_SIZE) {
569 ioContext->pos_ = newPos;
570 }
571 MEDIA_LOG_DD("current offset: " PUBLIC_LOG_D64 ", new pos: " PUBLIC_LOG_U64, ioContext->pos_, newPos);
572 return newPos;
573 }
574 } // Ffmpeg
575 } // Plugin
576 } // Media
577 } // OHOS