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 <fstream>
17#include <functional>
18#include <getopt.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23#include "codec_factory.h"
24#include "common/sharing_log.h"
25#include "frame.h"
26#include "media_frame_pipeline.h"
27
28using namespace OHOS::Sharing;
29
30char *gInFile = nullptr;
31char *gOutFile = nullptr;
32int gType = -1; // 0 for decode, 1 for encode
33
34void ShowUsage(char *exe)
35{
36    SHARING_LOGD("usage:\n%{public}s -t <type> -i <in file> -o <out file>", exe);
37    SHARING_LOGD("\t-t 0: decode G.711, 1: encode G.711, 2:decode AAC-ADTS");
38    SHARING_LOGD("\t-i in file");
39    SHARING_LOGD("\t-o out file");
40}
41
42int ParseParam(int argc, char *argv[])
43{
44    int ret;
45
46    while ((ret = getopt(argc, argv, ":t:i:o:")) != -1) {
47        switch (ret) {
48            case ('t'):
49                gType = atoi(optarg);
50                break;
51            case ('i'):
52                gInFile = optarg;
53                break;
54            case ('o'):
55                gOutFile = optarg;
56                break;
57            case ':':
58                SHARING_LOGD("option [-%c] requires an argument.", static_cast<char>(optopt));
59                break;
60            case '?':
61                SHARING_LOGD("unknown option: %c.", static_cast<char>(optopt));
62                break;
63            default:
64                break;
65        }
66    }
67
68    if ((gType > 2 || gType < 0) || gInFile == nullptr || gOutFile == nullptr) {
69        SHARING_LOGD("param error");
70        ShowUsage(argv[0]);
71        return -1;
72    }
73
74    return 0;
75}
76
77class RawDataReceiver : public FrameDestination {
78public:
79    RawDataReceiver(std::fstream &fd) : fd_(fd) {}
80    ~RawDataReceiver() = default;
81    void OnFrame(const Frame::Ptr &frame) override
82    {
83        fd_.write((char *)frame->Data(), frame->Size());
84        SHARING_LOGD("write data(%{public}p) len(%{public}d)", frame->Data(), frame->Size());
85    }
86
87private:
88    std::fstream &fd_;
89};
90
91void DecodeG711(char *data, int length, std::fstream &fd)
92{
93    std::shared_ptr<AudioDecoder> decoder = CodecFactory::CreateAudioDecoder(CODEC_G711A);
94    if (!decoder) {
95        return;
96    }
97    decoder->Init();
98
99    auto rawReceiver = std::make_shared<RawDataReceiver>(fd);
100
101    decoder->AddAudioDestination(rawReceiver);
102    auto g711Frame = FrameImpl::Create();
103    g711Frame->codecId_ = CODEC_G711A;
104    char *p = data;
105    for (int i = 0; i < length / 160; i++) {
106        SHARING_LOGD("for i(%{public}d)", i);
107        g711Frame->Clear();
108        g711Frame->Assign(p, 160);
109        decoder->OnFrame(g711Frame);
110        p += 160;
111    }
112    SHARING_LOGD("decodeG711 line(%{public}d).", __LINE__);
113}
114
115void DecodeAAC(char *data, int length, std::fstream &fd)
116{
117    std::shared_ptr<AudioDecoder> decoder = CodecFactory::CreateAudioDecoder(OHOS::Sharing::CODEC_AAC);
118    if (!decoder) {
119        return;
120    }
121    decoder->Init();
122
123    auto rawReceiver = std::make_shared<RawDataReceiver>(fd);
124
125    decoder->AddAudioDestination(rawReceiver);
126    auto aacFrame = FrameImpl::Create();
127    aacFrame->codecId_ = CODEC_AAC;
128    char *p = data;
129    for (int i = 0; i < length / 2048; i++) {
130        SHARING_LOGD("for i(%{public}d)", i);
131        aacFrame->Clear();
132        aacFrame->Assign(p, 2048);
133        decoder->OnFrame(aacFrame);
134        p += 2048;
135    }
136    SHARING_LOGD("decodeAAC line(%{public}d).", __LINE__);
137}
138
139void EncodeG711(char *data, int length, std::fstream &fd)
140{
141    std::shared_ptr<AudioEncoder> encoder = CodecFactory::CreateAudioEncoder(CODEC_G711A);
142    if (!encoder) {
143        return;
144    }
145    encoder->Init();
146
147    auto rawReceiver = std::make_shared<RawDataReceiver>(fd);
148
149    encoder->AddAudioDestination(rawReceiver);
150
151    auto pcmFrame = FrameImpl::Create();
152    pcmFrame->codecId_ = CODEC_PCM;
153    char *p = data;
154    for (int i = 0; i < length / 320; i++) {
155        SHARING_LOGD("for i(%{public}d)", i);
156        pcmFrame->Clear();
157        pcmFrame->Assign(p, 320);
158        encoder->OnFrame(pcmFrame);
159        p += 320;
160    }
161    SHARING_LOGD("decodeG711 line(%{public}d).", __LINE__);
162}
163
164int main(int argc, char *argv[])
165{
166    SHARING_LOGD("hello codec_demo.");
167    if (ParseParam(argc, argv) != 0) {
168        return -1;
169    }
170
171    std::fstream infile(gInFile, std::ios::in | std::ios_base::binary);
172    if (!infile.is_open()) {
173        SHARING_LOGD("failed to open file");
174        return -1;
175    }
176
177    std::fstream outfile(gOutFile, std::ios::out | std::ios_base::binary);
178    if (!outfile.is_open()) {
179        SHARING_LOGD("failed to open file");
180        return -1;
181    }
182
183    infile.seekg(0, std::ios::end);
184    int size = infile.tellg();
185    infile.seekg(0, std::ios::beg);
186
187    char *content = new char[size];
188    infile.read(content, size);
189    SHARING_LOGD("size %{public}d.", size);
190    infile.close();
191    if (gType == 0) {
192        DecodeG711(content, size, outfile);
193    } else if (gType == 1) {
194        EncodeG711(content, size, outfile);
195    } else if (gType == 2) {
196        DecodeAAC(content, size, outfile);
197    }
198
199    outfile.close();
200    delete[] content;
201}
202