1e0e9324cSopenharmony_ci/*
2e0e9324cSopenharmony_ci * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3e0e9324cSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e0e9324cSopenharmony_ci * you may not use this file except in compliance with the License.
5e0e9324cSopenharmony_ci * You may obtain a copy of the License at
6e0e9324cSopenharmony_ci *
7e0e9324cSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e0e9324cSopenharmony_ci *
9e0e9324cSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e0e9324cSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e0e9324cSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e0e9324cSopenharmony_ci * See the License for the specific language governing permissions and
13e0e9324cSopenharmony_ci * limitations under the License.
14e0e9324cSopenharmony_ci */
15e0e9324cSopenharmony_ci
16e0e9324cSopenharmony_ci#include "frame_merger.h"
17e0e9324cSopenharmony_ci#include <arpa/inet.h>
18e0e9324cSopenharmony_ci#include "common/common_macro.h"
19e0e9324cSopenharmony_ci
20e0e9324cSopenharmony_cinamespace OHOS {
21e0e9324cSopenharmony_cinamespace Sharing {
22e0e9324cSopenharmony_cistatic size_t constexpr MAX_FRAME_CACHE_SIZE = 100;
23e0e9324cSopenharmony_ci
24e0e9324cSopenharmony_civoid FrameMerger::Clear()
25e0e9324cSopenharmony_ci{
26e0e9324cSopenharmony_ci    frameCache_.clear();
27e0e9324cSopenharmony_ci    haveDecodeAbleFrame_ = false;
28e0e9324cSopenharmony_ci}
29e0e9324cSopenharmony_ci
30e0e9324cSopenharmony_civoid FrameMerger::SetType(int32_t type)
31e0e9324cSopenharmony_ci{
32e0e9324cSopenharmony_ci    type_ = type;
33e0e9324cSopenharmony_ci}
34e0e9324cSopenharmony_ci
35e0e9324cSopenharmony_cibool FrameMerger::InputFrame(const Frame::Ptr &frame, DataBuffer::Ptr &buffer, const onOutput &cb)
36e0e9324cSopenharmony_ci{
37e0e9324cSopenharmony_ci    if (buffer == nullptr) {
38e0e9324cSopenharmony_ci        return false;
39e0e9324cSopenharmony_ci    }
40e0e9324cSopenharmony_ci    RETURN_FALSE_IF_NULL(buffer);
41e0e9324cSopenharmony_ci
42e0e9324cSopenharmony_ci    if (WillFlush(frame)) {
43e0e9324cSopenharmony_ci        if (frameCache_.empty()) {
44e0e9324cSopenharmony_ci            return false;
45e0e9324cSopenharmony_ci        }
46e0e9324cSopenharmony_ci        Frame::Ptr back = frameCache_.back();
47e0e9324cSopenharmony_ci        RETURN_FALSE_IF_NULL(back);
48e0e9324cSopenharmony_ci        bool haveKeyFrame = back->KeyFrame();
49e0e9324cSopenharmony_ci        if (frameCache_.size() != 1 || type_ == MP4_NAL_SIZE || buffer) {
50e0e9324cSopenharmony_ci            DataBuffer::Ptr &merged = buffer;
51e0e9324cSopenharmony_ci
52e0e9324cSopenharmony_ci            for (auto &&vframe : frameCache_) {
53e0e9324cSopenharmony_ci                DoMerge(merged, vframe);
54e0e9324cSopenharmony_ci                if (vframe->KeyFrame()) {
55e0e9324cSopenharmony_ci                    haveKeyFrame = true;
56e0e9324cSopenharmony_ci                }
57e0e9324cSopenharmony_ci            }
58e0e9324cSopenharmony_ci        }
59e0e9324cSopenharmony_ci        cb(back->Dts(), back->Pts(), buffer, haveKeyFrame);
60e0e9324cSopenharmony_ci        frameCache_.clear();
61e0e9324cSopenharmony_ci        haveDecodeAbleFrame_ = false;
62e0e9324cSopenharmony_ci    }
63e0e9324cSopenharmony_ci
64e0e9324cSopenharmony_ci    if (!frame) {
65e0e9324cSopenharmony_ci        return false;
66e0e9324cSopenharmony_ci    }
67e0e9324cSopenharmony_ci
68e0e9324cSopenharmony_ci    if (frame->DecodeAble()) {
69e0e9324cSopenharmony_ci        haveDecodeAbleFrame_ = true;
70e0e9324cSopenharmony_ci    }
71e0e9324cSopenharmony_ci    frameCache_.emplace_back(frame);
72e0e9324cSopenharmony_ci    return true;
73e0e9324cSopenharmony_ci}
74e0e9324cSopenharmony_ci
75e0e9324cSopenharmony_cibool FrameMerger::WillFlush(const Frame::Ptr &frame) const
76e0e9324cSopenharmony_ci{
77e0e9324cSopenharmony_ci    if (frameCache_.empty()) {
78e0e9324cSopenharmony_ci        return false;
79e0e9324cSopenharmony_ci    }
80e0e9324cSopenharmony_ci    if (!frame) {
81e0e9324cSopenharmony_ci        return true;
82e0e9324cSopenharmony_ci    }
83e0e9324cSopenharmony_ci    switch (type_) {
84e0e9324cSopenharmony_ci        case NONE: {
85e0e9324cSopenharmony_ci            bool newFrame = false;
86e0e9324cSopenharmony_ci            switch (frame->GetCodecId()) {
87e0e9324cSopenharmony_ci                case CODEC_H264:
88e0e9324cSopenharmony_ci                case CODEC_H265: {
89e0e9324cSopenharmony_ci                    newFrame = frame->PrefixSize();
90e0e9324cSopenharmony_ci                    break;
91e0e9324cSopenharmony_ci                }
92e0e9324cSopenharmony_ci                default:
93e0e9324cSopenharmony_ci                    break;
94e0e9324cSopenharmony_ci            }
95e0e9324cSopenharmony_ci
96e0e9324cSopenharmony_ci            return newFrame || frameCache_.back()->Dts() != frame->Dts() || frameCache_.size() > MAX_FRAME_CACHE_SIZE;
97e0e9324cSopenharmony_ci        }
98e0e9324cSopenharmony_ci
99e0e9324cSopenharmony_ci        case MP4_NAL_SIZE:
100e0e9324cSopenharmony_ci        case H264_PREFIX: {
101e0e9324cSopenharmony_ci            if (!haveDecodeAbleFrame_) {
102e0e9324cSopenharmony_ci                return frameCache_.size() > MAX_FRAME_CACHE_SIZE;
103e0e9324cSopenharmony_ci            }
104e0e9324cSopenharmony_ci            if (frameCache_.back()->Dts() != frame->Dts() || frame->DecodeAble() || frame->ConfigFrame()) {
105e0e9324cSopenharmony_ci                return true;
106e0e9324cSopenharmony_ci            }
107e0e9324cSopenharmony_ci
108e0e9324cSopenharmony_ci            return frameCache_.size() > MAX_FRAME_CACHE_SIZE;
109e0e9324cSopenharmony_ci        }
110e0e9324cSopenharmony_ci        default:
111e0e9324cSopenharmony_ci            return false;
112e0e9324cSopenharmony_ci    }
113e0e9324cSopenharmony_ci}
114e0e9324cSopenharmony_ci
115e0e9324cSopenharmony_civoid FrameMerger::DoMerge(DataBuffer::Ptr &merged, const Frame::Ptr &frame) const
116e0e9324cSopenharmony_ci{
117e0e9324cSopenharmony_ci    RETURN_IF_NULL(merged);
118e0e9324cSopenharmony_ci    RETURN_IF_NULL(frame);
119e0e9324cSopenharmony_ci    switch (type_) {
120e0e9324cSopenharmony_ci        case NONE: {
121e0e9324cSopenharmony_ci            merged->Append(frame->Data(), frame->Size());
122e0e9324cSopenharmony_ci            break;
123e0e9324cSopenharmony_ci        }
124e0e9324cSopenharmony_ci        case H264_PREFIX: {
125e0e9324cSopenharmony_ci            if (frame->PrefixSize()) {
126e0e9324cSopenharmony_ci                merged->Append(frame->Data(), frame->Size());
127e0e9324cSopenharmony_ci            } else {
128e0e9324cSopenharmony_ci                merged->Append("\x00\x00\x00\x01", 4); // 4:avc start code size
129e0e9324cSopenharmony_ci                merged->Append(frame->Data(), frame->Size());
130e0e9324cSopenharmony_ci            }
131e0e9324cSopenharmony_ci            break;
132e0e9324cSopenharmony_ci        }
133e0e9324cSopenharmony_ci        case MP4_NAL_SIZE: {
134e0e9324cSopenharmony_ci            uint32_t naluSize = (uint32_t)(frame->Size() - frame->PrefixSize());
135e0e9324cSopenharmony_ci            naluSize = htonl(naluSize);
136e0e9324cSopenharmony_ci            merged->Append((char *)&naluSize, 4); // 4:avc start code size
137e0e9324cSopenharmony_ci            merged->Append(frame->Data() + frame->PrefixSize(), frame->Size() - frame->PrefixSize());
138e0e9324cSopenharmony_ci            break;
139e0e9324cSopenharmony_ci        }
140e0e9324cSopenharmony_ci        default:
141e0e9324cSopenharmony_ci            break;
142e0e9324cSopenharmony_ci    }
143e0e9324cSopenharmony_ci}
144e0e9324cSopenharmony_ci} // namespace Sharing
145e0e9324cSopenharmony_ci} // namespace OHOS