1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2015 Ludmila Glinskih
3cabdff1aSopenharmony_ci * Copyright (c) 2001 Fabrice Bellard
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
6cabdff1aSopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
7cabdff1aSopenharmony_ci * in the Software without restriction, including without limitation the rights
8cabdff1aSopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9cabdff1aSopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
10cabdff1aSopenharmony_ci * furnished to do so, subject to the following conditions:
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * The above copyright notice and this permission notice shall be included in
13cabdff1aSopenharmony_ci * all copies or substantial portions of the Software.
14cabdff1aSopenharmony_ci *
15cabdff1aSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16cabdff1aSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17cabdff1aSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18cabdff1aSopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19cabdff1aSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20cabdff1aSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21cabdff1aSopenharmony_ci * THE SOFTWARE.
22cabdff1aSopenharmony_ci */
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci/*
25cabdff1aSopenharmony_ci * FLAC codec test.
26cabdff1aSopenharmony_ci * Encodes raw data to FLAC format and decodes it back to raw. Compares raw-data
27cabdff1aSopenharmony_ci * after that.
28cabdff1aSopenharmony_ci */
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "libavcodec/avcodec.h"
31cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h"
32cabdff1aSopenharmony_ci#include "libavutil/common.h"
33cabdff1aSopenharmony_ci#include "libavutil/samplefmt.h"
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_ci#define NUMBER_OF_AUDIO_FRAMES 200
36cabdff1aSopenharmony_ci#define NAME_BUFF_SIZE 100
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_ci/* generate i-th frame of test audio */
39cabdff1aSopenharmony_cistatic int generate_raw_frame(uint16_t *frame_data, int i, int sample_rate,
40cabdff1aSopenharmony_ci                              int channels, int frame_size)
41cabdff1aSopenharmony_ci{
42cabdff1aSopenharmony_ci    int j, k;
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci    for (j = 0; j < frame_size; j++) {
45cabdff1aSopenharmony_ci        frame_data[channels * j] = 10000 * ((j / 10 * i) % 2);
46cabdff1aSopenharmony_ci        for (k = 1; k < channels; k++)
47cabdff1aSopenharmony_ci            frame_data[channels * j + k] = frame_data[channels * j] * (k + 1);
48cabdff1aSopenharmony_ci    }
49cabdff1aSopenharmony_ci    return 0;
50cabdff1aSopenharmony_ci}
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_cistatic int init_encoder(const AVCodec *enc, AVCodecContext **enc_ctx,
53cabdff1aSopenharmony_ci                        const AVChannelLayout *ch_layout, int sample_rate)
54cabdff1aSopenharmony_ci{
55cabdff1aSopenharmony_ci    AVCodecContext *ctx;
56cabdff1aSopenharmony_ci    int result;
57cabdff1aSopenharmony_ci    char name_buff[NAME_BUFF_SIZE];
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ci    av_channel_layout_describe(ch_layout, name_buff, NAME_BUFF_SIZE);
60cabdff1aSopenharmony_ci    av_log(NULL, AV_LOG_INFO, "channel layout: %s, sample rate: %i\n", name_buff, sample_rate);
61cabdff1aSopenharmony_ci
62cabdff1aSopenharmony_ci    ctx = avcodec_alloc_context3(enc);
63cabdff1aSopenharmony_ci    if (!ctx) {
64cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't allocate encoder context\n");
65cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
66cabdff1aSopenharmony_ci    }
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci    ctx->sample_fmt = AV_SAMPLE_FMT_S16;
69cabdff1aSopenharmony_ci    ctx->sample_rate = sample_rate;
70cabdff1aSopenharmony_ci    av_channel_layout_copy(&ctx->ch_layout, ch_layout);
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_ci    result = avcodec_open2(ctx, enc, NULL);
73cabdff1aSopenharmony_ci    if (result < 0) {
74cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Can't open encoder\n");
75cabdff1aSopenharmony_ci        return result;
76cabdff1aSopenharmony_ci    }
77cabdff1aSopenharmony_ci
78cabdff1aSopenharmony_ci    *enc_ctx = ctx;
79cabdff1aSopenharmony_ci    return 0;
80cabdff1aSopenharmony_ci}
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_cistatic int init_decoder(const AVCodec *dec, AVCodecContext **dec_ctx,
83cabdff1aSopenharmony_ci                        const AVChannelLayout *ch_layout)
84cabdff1aSopenharmony_ci{
85cabdff1aSopenharmony_ci    AVCodecContext *ctx;
86cabdff1aSopenharmony_ci    int result;
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_ci    ctx = avcodec_alloc_context3(dec);
89cabdff1aSopenharmony_ci    if (!ctx) {
90cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR , "Can't allocate decoder context\n");
91cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
92cabdff1aSopenharmony_ci    }
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_ci    ctx->request_sample_fmt = AV_SAMPLE_FMT_S16;
95cabdff1aSopenharmony_ci    av_channel_layout_copy(&ctx->ch_layout, ch_layout);
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ci    result = avcodec_open2(ctx, dec, NULL);
98cabdff1aSopenharmony_ci    if (result < 0) {
99cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Can't open decoder\n");
100cabdff1aSopenharmony_ci        return result;
101cabdff1aSopenharmony_ci    }
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci    *dec_ctx = ctx;
104cabdff1aSopenharmony_ci    return 0;
105cabdff1aSopenharmony_ci}
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_cistatic int run_test(const AVCodec *enc, const AVCodec *dec,
108cabdff1aSopenharmony_ci                    AVCodecContext *enc_ctx, AVCodecContext *dec_ctx)
109cabdff1aSopenharmony_ci{
110cabdff1aSopenharmony_ci    AVPacket *enc_pkt;
111cabdff1aSopenharmony_ci    AVFrame *in_frame, *out_frame;
112cabdff1aSopenharmony_ci    uint8_t *raw_in = NULL, *raw_out = NULL;
113cabdff1aSopenharmony_ci    int in_offset = 0, out_offset = 0;
114cabdff1aSopenharmony_ci    int result = 0;
115cabdff1aSopenharmony_ci    int i = 0;
116cabdff1aSopenharmony_ci    int in_frame_bytes, out_frame_bytes;
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    enc_pkt = av_packet_alloc();
119cabdff1aSopenharmony_ci    if (!enc_pkt) {
120cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't allocate output packet\n");
121cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
122cabdff1aSopenharmony_ci    }
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_ci    in_frame = av_frame_alloc();
125cabdff1aSopenharmony_ci    if (!in_frame) {
126cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't allocate input frame\n");
127cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
128cabdff1aSopenharmony_ci    }
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_ci    in_frame->nb_samples = enc_ctx->frame_size;
131cabdff1aSopenharmony_ci    in_frame->format = enc_ctx->sample_fmt;
132cabdff1aSopenharmony_ci    result = av_channel_layout_copy(&in_frame->ch_layout, &enc_ctx->ch_layout);
133cabdff1aSopenharmony_ci    if (result < 0)
134cabdff1aSopenharmony_ci        return result;
135cabdff1aSopenharmony_ci    if (av_frame_get_buffer(in_frame, 0) != 0) {
136cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't allocate a buffer for input frame\n");
137cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
138cabdff1aSopenharmony_ci    }
139cabdff1aSopenharmony_ci
140cabdff1aSopenharmony_ci    out_frame = av_frame_alloc();
141cabdff1aSopenharmony_ci    if (!out_frame) {
142cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't allocate output frame\n");
143cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
144cabdff1aSopenharmony_ci    }
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_ci    raw_in = av_malloc(in_frame->linesize[0] * NUMBER_OF_AUDIO_FRAMES);
147cabdff1aSopenharmony_ci    if (!raw_in) {
148cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_in\n");
149cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
150cabdff1aSopenharmony_ci    }
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_ci    raw_out = av_malloc(in_frame->linesize[0] * NUMBER_OF_AUDIO_FRAMES);
153cabdff1aSopenharmony_ci    if (!raw_out) {
154cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_out\n");
155cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
156cabdff1aSopenharmony_ci    }
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci    for (i = 0; i < NUMBER_OF_AUDIO_FRAMES; i++) {
159cabdff1aSopenharmony_ci        result = av_frame_make_writable(in_frame);
160cabdff1aSopenharmony_ci        if (result < 0)
161cabdff1aSopenharmony_ci            return result;
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_ci        generate_raw_frame((uint16_t*)(in_frame->data[0]), i, enc_ctx->sample_rate,
164cabdff1aSopenharmony_ci                           enc_ctx->ch_layout.nb_channels, enc_ctx->frame_size);
165cabdff1aSopenharmony_ci        in_frame_bytes = in_frame->nb_samples * in_frame->ch_layout.nb_channels * sizeof(uint16_t);
166cabdff1aSopenharmony_ci        if (in_frame_bytes > in_frame->linesize[0]) {
167cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_ERROR, "Incorrect value of input frame linesize\n");
168cabdff1aSopenharmony_ci            return 1;
169cabdff1aSopenharmony_ci        }
170cabdff1aSopenharmony_ci        memcpy(raw_in + in_offset, in_frame->data[0], in_frame_bytes);
171cabdff1aSopenharmony_ci        in_offset += in_frame_bytes;
172cabdff1aSopenharmony_ci        result = avcodec_send_frame(enc_ctx, in_frame);
173cabdff1aSopenharmony_ci        if (result < 0) {
174cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_ERROR, "Error submitting a frame for encoding\n");
175cabdff1aSopenharmony_ci            return result;
176cabdff1aSopenharmony_ci        }
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci        while (result >= 0) {
179cabdff1aSopenharmony_ci            result = avcodec_receive_packet(enc_ctx, enc_pkt);
180cabdff1aSopenharmony_ci            if (result == AVERROR(EAGAIN))
181cabdff1aSopenharmony_ci                break;
182cabdff1aSopenharmony_ci            else if (result < 0 && result != AVERROR_EOF) {
183cabdff1aSopenharmony_ci                av_log(NULL, AV_LOG_ERROR, "Error encoding audio frame\n");
184cabdff1aSopenharmony_ci                return result;
185cabdff1aSopenharmony_ci            }
186cabdff1aSopenharmony_ci
187cabdff1aSopenharmony_ci            /* if we get an encoded packet, feed it straight to the decoder */
188cabdff1aSopenharmony_ci            result = avcodec_send_packet(dec_ctx, enc_pkt);
189cabdff1aSopenharmony_ci            av_packet_unref(enc_pkt);
190cabdff1aSopenharmony_ci            if (result < 0) {
191cabdff1aSopenharmony_ci                av_log(NULL, AV_LOG_ERROR, "Error submitting a packet for decoding\n");
192cabdff1aSopenharmony_ci                return result;
193cabdff1aSopenharmony_ci            }
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci            result = avcodec_receive_frame(dec_ctx, out_frame);
196cabdff1aSopenharmony_ci            if (result == AVERROR(EAGAIN)) {
197cabdff1aSopenharmony_ci                result = 0;
198cabdff1aSopenharmony_ci                continue;
199cabdff1aSopenharmony_ci            } else if (result == AVERROR(EOF)) {
200cabdff1aSopenharmony_ci                result = 0;
201cabdff1aSopenharmony_ci                break;
202cabdff1aSopenharmony_ci            } else if (result < 0) {
203cabdff1aSopenharmony_ci                av_log(NULL, AV_LOG_ERROR, "Error decoding audio packet\n");
204cabdff1aSopenharmony_ci                return result;
205cabdff1aSopenharmony_ci            }
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci            if (in_frame->nb_samples != out_frame->nb_samples) {
208cabdff1aSopenharmony_ci                av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different number of samples\n");
209cabdff1aSopenharmony_ci                return AVERROR_UNKNOWN;
210cabdff1aSopenharmony_ci            }
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci            if (av_channel_layout_compare(&in_frame->ch_layout, &out_frame->ch_layout)) {
213cabdff1aSopenharmony_ci                av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different channel layout\n");
214cabdff1aSopenharmony_ci                return AVERROR_UNKNOWN;
215cabdff1aSopenharmony_ci            }
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci            if (in_frame->format != out_frame->format) {
218cabdff1aSopenharmony_ci                av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different sample format\n");
219cabdff1aSopenharmony_ci                return AVERROR_UNKNOWN;
220cabdff1aSopenharmony_ci            }
221cabdff1aSopenharmony_ci            out_frame_bytes = out_frame->nb_samples * out_frame->ch_layout.nb_channels * sizeof(uint16_t);
222cabdff1aSopenharmony_ci            if (out_frame_bytes > out_frame->linesize[0]) {
223cabdff1aSopenharmony_ci                av_log(NULL, AV_LOG_ERROR, "Incorrect value of output frame linesize\n");
224cabdff1aSopenharmony_ci                return 1;
225cabdff1aSopenharmony_ci            }
226cabdff1aSopenharmony_ci            memcpy(raw_out + out_offset, out_frame->data[0], out_frame_bytes);
227cabdff1aSopenharmony_ci            out_offset += out_frame_bytes;
228cabdff1aSopenharmony_ci        }
229cabdff1aSopenharmony_ci    }
230cabdff1aSopenharmony_ci
231cabdff1aSopenharmony_ci    if (memcmp(raw_in, raw_out, out_frame_bytes * NUMBER_OF_AUDIO_FRAMES) != 0) {
232cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Output differs\n");
233cabdff1aSopenharmony_ci        return 1;
234cabdff1aSopenharmony_ci    }
235cabdff1aSopenharmony_ci
236cabdff1aSopenharmony_ci    av_log(NULL, AV_LOG_INFO, "OK\n");
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    av_freep(&raw_in);
239cabdff1aSopenharmony_ci    av_freep(&raw_out);
240cabdff1aSopenharmony_ci    av_packet_free(&enc_pkt);
241cabdff1aSopenharmony_ci    av_frame_free(&in_frame);
242cabdff1aSopenharmony_ci    av_frame_free(&out_frame);
243cabdff1aSopenharmony_ci    return 0;
244cabdff1aSopenharmony_ci}
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_ciint main(void)
247cabdff1aSopenharmony_ci{
248cabdff1aSopenharmony_ci    const AVCodec *enc = NULL, *dec = NULL;
249cabdff1aSopenharmony_ci    AVCodecContext *enc_ctx = NULL, *dec_ctx = NULL;
250cabdff1aSopenharmony_ci    const AVChannelLayout channel_layouts[] = { AV_CHANNEL_LAYOUT_STEREO,
251cabdff1aSopenharmony_ci                                                AV_CHANNEL_LAYOUT_5POINT1_BACK,
252cabdff1aSopenharmony_ci                                                AV_CHANNEL_LAYOUT_SURROUND,
253cabdff1aSopenharmony_ci                                                AV_CHANNEL_LAYOUT_STEREO_DOWNMIX };
254cabdff1aSopenharmony_ci    int sample_rates[] = {8000, 44100, 48000, 192000};
255cabdff1aSopenharmony_ci    int cl, sr;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    enc = avcodec_find_encoder(AV_CODEC_ID_FLAC);
258cabdff1aSopenharmony_ci    if (!enc) {
259cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't find encoder\n");
260cabdff1aSopenharmony_ci        return 1;
261cabdff1aSopenharmony_ci    }
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ci    dec = avcodec_find_decoder(AV_CODEC_ID_FLAC);
264cabdff1aSopenharmony_ci    if (!dec) {
265cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Can't find decoder\n");
266cabdff1aSopenharmony_ci        return 1;
267cabdff1aSopenharmony_ci    }
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci    for (cl = 0; cl < FF_ARRAY_ELEMS(channel_layouts); cl++) {
270cabdff1aSopenharmony_ci        for (sr = 0; sr < FF_ARRAY_ELEMS(sample_rates); sr++) {
271cabdff1aSopenharmony_ci            if (init_encoder(enc, &enc_ctx, &channel_layouts[cl], sample_rates[sr]) != 0)
272cabdff1aSopenharmony_ci                return 1;
273cabdff1aSopenharmony_ci            if (init_decoder(dec, &dec_ctx, &channel_layouts[cl]) != 0)
274cabdff1aSopenharmony_ci                return 1;
275cabdff1aSopenharmony_ci            if (run_test(enc, dec, enc_ctx, dec_ctx) != 0)
276cabdff1aSopenharmony_ci                return 1;
277cabdff1aSopenharmony_ci            avcodec_free_context(&enc_ctx);
278cabdff1aSopenharmony_ci            avcodec_free_context(&dec_ctx);
279cabdff1aSopenharmony_ci        }
280cabdff1aSopenharmony_ci    }
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_ci    return 0;
283cabdff1aSopenharmony_ci}
284