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