• 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 
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