• 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     RETURN_FALSE_IF_NULL(buffer);
38 
39     if (WillFlush(frame)) {
40         if (frameCache_.empty()) {
41             return false;
42         }
43         Frame::Ptr back = frameCache_.back();
44         RETURN_FALSE_IF_NULL(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     RETURN_IF_NULL(merged);
115     RETURN_IF_NULL(frame);
116     switch (type_) {
117         case NONE: {
118             merged->Append(frame->Data(), frame->Size());
119             break;
120         }
121         case H264_PREFIX: {
122             if (frame->PrefixSize()) {
123                 merged->Append(frame->Data(), frame->Size());
124             } else {
125                 merged->Append("\x00\x00\x00\x01", 4); // 4:avc start code size
126                 merged->Append(frame->Data(), frame->Size());
127             }
128             break;
129         }
130         case MP4_NAL_SIZE: {
131             uint32_t naluSize = (uint32_t)((size_t)frame->Size() - frame->PrefixSize());
132             naluSize = htonl(naluSize);
133             merged->Append((char *)&naluSize, 4); // 4:avc start code size
134             merged->Append(frame->Data() + frame->PrefixSize(), frame->Size() - frame->PrefixSize());
135             break;
136         }
137         default:
138             break;
139     }
140 }
141 } // namespace Sharing
142 } // namespace OHOS