• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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