1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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 "frame_merger.h"
17 #include <arpa/inet.h>
18 #include "common/common_macro.h"
19
20 namespace OHOS {
21 namespace Sharing {
22 static size_t constexpr MAX_FRAME_CACHE_SIZE = 100;
23
Clear()24 void FrameMerger::Clear()
25 {
26 frameCache_.clear();
27 haveDecodeAbleFrame_ = false;
28 }
29
SetType(int32_t type)30 void FrameMerger::SetType(int32_t type)
31 {
32 type_ = type;
33 }
34
InputFrame(const Frame::Ptr & frame,DataBuffer::Ptr & buffer,const onOutput & cb)35 bool FrameMerger::InputFrame(const Frame::Ptr &frame, DataBuffer::Ptr &buffer, const onOutput &cb)
36 {
37 if (buffer == nullptr) {
38 return false;
39 }
40 RETURN_FALSE_IF_NULL(buffer);
41
42 if (WillFlush(frame)) {
43 if (frameCache_.empty()) {
44 return false;
45 }
46 Frame::Ptr back = frameCache_.back();
47 RETURN_FALSE_IF_NULL(back);
48 bool haveKeyFrame = back->KeyFrame();
49 if (frameCache_.size() != 1 || type_ == MP4_NAL_SIZE || buffer) {
50 DataBuffer::Ptr &merged = buffer;
51
52 for (auto &&vframe : frameCache_) {
53 DoMerge(merged, vframe);
54 if (vframe->KeyFrame()) {
55 haveKeyFrame = true;
56 }
57 }
58 }
59 cb(back->Dts(), back->Pts(), buffer, haveKeyFrame);
60 frameCache_.clear();
61 haveDecodeAbleFrame_ = false;
62 }
63
64 if (!frame) {
65 return false;
66 }
67
68 if (frame->DecodeAble()) {
69 haveDecodeAbleFrame_ = true;
70 }
71 frameCache_.emplace_back(frame);
72 return true;
73 }
74
WillFlush(const Frame::Ptr & frame) const75 bool FrameMerger::WillFlush(const Frame::Ptr &frame) const
76 {
77 if (frameCache_.empty()) {
78 return false;
79 }
80 if (!frame) {
81 return true;
82 }
83 switch (type_) {
84 case NONE: {
85 bool newFrame = false;
86 switch (frame->GetCodecId()) {
87 case CODEC_H264:
88 case CODEC_H265: {
89 newFrame = frame->PrefixSize();
90 break;
91 }
92 default:
93 break;
94 }
95
96 return newFrame || frameCache_.back()->Dts() != frame->Dts() || frameCache_.size() > MAX_FRAME_CACHE_SIZE;
97 }
98
99 case MP4_NAL_SIZE:
100 case H264_PREFIX: {
101 if (!haveDecodeAbleFrame_) {
102 return frameCache_.size() > MAX_FRAME_CACHE_SIZE;
103 }
104 if (frameCache_.back()->Dts() != frame->Dts() || frame->DecodeAble() || frame->ConfigFrame()) {
105 return true;
106 }
107
108 return frameCache_.size() > MAX_FRAME_CACHE_SIZE;
109 }
110 default:
111 return false;
112 }
113 }
114
DoMerge(DataBuffer::Ptr & merged,const Frame::Ptr & frame) const115 void FrameMerger::DoMerge(DataBuffer::Ptr &merged, const Frame::Ptr &frame) const
116 {
117 RETURN_IF_NULL(merged);
118 RETURN_IF_NULL(frame);
119 switch (type_) {
120 case NONE: {
121 merged->Append(frame->Data(), frame->Size());
122 break;
123 }
124 case H264_PREFIX: {
125 if (frame->PrefixSize()) {
126 merged->Append(frame->Data(), frame->Size());
127 } else {
128 merged->Append("\x00\x00\x00\x01", 4); // 4:avc start code size
129 merged->Append(frame->Data(), frame->Size());
130 }
131 break;
132 }
133 case MP4_NAL_SIZE: {
134 uint32_t naluSize = (uint32_t)(frame->Size() - frame->PrefixSize());
135 naluSize = htonl(naluSize);
136 merged->Append((char *)&naluSize, 4); // 4:avc start code size
137 merged->Append(frame->Data() + frame->PrefixSize(), frame->Size() - frame->PrefixSize());
138 break;
139 }
140 default:
141 break;
142 }
143 }
144 } // namespace Sharing
145 } // namespace OHOS