1/*
2 * Copyright (c) 2001 Fabrice Bellard
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23/**
24 * @file
25 * audio decoding with libavcodec API example
26 *
27 * @example decode_audio.c
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <libavutil/frame.h>
35#include <libavutil/mem.h>
36
37#include <libavcodec/avcodec.h>
38
39#define AUDIO_INBUF_SIZE 20480
40#define AUDIO_REFILL_THRESH 4096
41
42static int get_format_from_sample_fmt(const char **fmt,
43                                      enum AVSampleFormat sample_fmt)
44{
45    int i;
46    struct sample_fmt_entry {
47        enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
48    } sample_fmt_entries[] = {
49        { AV_SAMPLE_FMT_U8,  "u8",    "u8"    },
50        { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
51        { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
52        { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
53        { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
54    };
55    *fmt = NULL;
56
57    for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
58        struct sample_fmt_entry *entry = &sample_fmt_entries[i];
59        if (sample_fmt == entry->sample_fmt) {
60            *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
61            return 0;
62        }
63    }
64
65    fprintf(stderr,
66            "sample format %s is not supported as output format\n",
67            av_get_sample_fmt_name(sample_fmt));
68    return -1;
69}
70
71static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame,
72                   FILE *outfile)
73{
74    int i, ch;
75    int ret, data_size;
76
77    /* send the packet with the compressed data to the decoder */
78    ret = avcodec_send_packet(dec_ctx, pkt);
79    if (ret < 0) {
80        fprintf(stderr, "Error submitting the packet to the decoder\n");
81        exit(1);
82    }
83
84    /* read all the output frames (in general there may be any number of them */
85    while (ret >= 0) {
86        ret = avcodec_receive_frame(dec_ctx, frame);
87        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
88            return;
89        else if (ret < 0) {
90            fprintf(stderr, "Error during decoding\n");
91            exit(1);
92        }
93        data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
94        if (data_size < 0) {
95            /* This should not occur, checking just for paranoia */
96            fprintf(stderr, "Failed to calculate data size\n");
97            exit(1);
98        }
99        for (i = 0; i < frame->nb_samples; i++)
100            for (ch = 0; ch < dec_ctx->ch_layout.nb_channels; ch++)
101                fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);
102    }
103}
104
105int main(int argc, char **argv)
106{
107    const char *outfilename, *filename;
108    const AVCodec *codec;
109    AVCodecContext *c= NULL;
110    AVCodecParserContext *parser = NULL;
111    int len, ret;
112    FILE *f, *outfile;
113    uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
114    uint8_t *data;
115    size_t   data_size;
116    AVPacket *pkt;
117    AVFrame *decoded_frame = NULL;
118    enum AVSampleFormat sfmt;
119    int n_channels = 0;
120    const char *fmt;
121
122    if (argc <= 2) {
123        fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
124        exit(0);
125    }
126    filename    = argv[1];
127    outfilename = argv[2];
128
129    pkt = av_packet_alloc();
130
131    /* find the MPEG audio decoder */
132    codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
133    if (!codec) {
134        fprintf(stderr, "Codec not found\n");
135        exit(1);
136    }
137
138    parser = av_parser_init(codec->id);
139    if (!parser) {
140        fprintf(stderr, "Parser not found\n");
141        exit(1);
142    }
143
144    c = avcodec_alloc_context3(codec);
145    if (!c) {
146        fprintf(stderr, "Could not allocate audio codec context\n");
147        exit(1);
148    }
149
150    /* open it */
151    if (avcodec_open2(c, codec, NULL) < 0) {
152        fprintf(stderr, "Could not open codec\n");
153        exit(1);
154    }
155
156    f = fopen(filename, "rb");
157    if (!f) {
158        fprintf(stderr, "Could not open %s\n", filename);
159        exit(1);
160    }
161    outfile = fopen(outfilename, "wb");
162    if (!outfile) {
163        av_free(c);
164        exit(1);
165    }
166
167    /* decode until eof */
168    data      = inbuf;
169    data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
170
171    while (data_size > 0) {
172        if (!decoded_frame) {
173            if (!(decoded_frame = av_frame_alloc())) {
174                fprintf(stderr, "Could not allocate audio frame\n");
175                exit(1);
176            }
177        }
178
179        ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
180                               data, data_size,
181                               AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
182        if (ret < 0) {
183            fprintf(stderr, "Error while parsing\n");
184            exit(1);
185        }
186        data      += ret;
187        data_size -= ret;
188
189        if (pkt->size)
190            decode(c, pkt, decoded_frame, outfile);
191
192        if (data_size < AUDIO_REFILL_THRESH) {
193            memmove(inbuf, data, data_size);
194            data = inbuf;
195            len = fread(data + data_size, 1,
196                        AUDIO_INBUF_SIZE - data_size, f);
197            if (len > 0)
198                data_size += len;
199        }
200    }
201
202    /* flush the decoder */
203    pkt->data = NULL;
204    pkt->size = 0;
205    decode(c, pkt, decoded_frame, outfile);
206
207    /* print output pcm infomations, because there have no metadata of pcm */
208    sfmt = c->sample_fmt;
209
210    if (av_sample_fmt_is_planar(sfmt)) {
211        const char *packed = av_get_sample_fmt_name(sfmt);
212        printf("Warning: the sample format the decoder produced is planar "
213               "(%s). This example will output the first channel only.\n",
214               packed ? packed : "?");
215        sfmt = av_get_packed_sample_fmt(sfmt);
216    }
217
218    n_channels = c->ch_layout.nb_channels;
219    if ((ret = get_format_from_sample_fmt(&fmt, sfmt)) < 0)
220        goto end;
221
222    printf("Play the output audio file with the command:\n"
223           "ffplay -f %s -ac %d -ar %d %s\n",
224           fmt, n_channels, c->sample_rate,
225           outfilename);
226end:
227    fclose(outfile);
228    fclose(f);
229
230    avcodec_free_context(&c);
231    av_parser_close(parser);
232    av_frame_free(&decoded_frame);
233    av_packet_free(&pkt);
234
235    return 0;
236}
237