Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * iLBC storage file format
3
 * Copyright (c) 2012 Martin Storsjo
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
 
22
#include "avformat.h"
23
#include "internal.h"
24
 
25
static const char mode20_header[] = "#!iLBC20\n";
26
static const char mode30_header[] = "#!iLBC30\n";
27
 
28
static int ilbc_write_header(AVFormatContext *s)
29
{
30
    AVIOContext *pb = s->pb;
31
    AVCodecContext *enc;
32
 
33
    if (s->nb_streams != 1) {
34
        av_log(s, AV_LOG_ERROR, "Unsupported number of streams\n");
35
        return AVERROR(EINVAL);
36
    }
37
    enc = s->streams[0]->codec;
38
 
39
    if (enc->codec_id != AV_CODEC_ID_ILBC) {
40
        av_log(s, AV_LOG_ERROR, "Unsupported codec\n");
41
        return AVERROR(EINVAL);
42
    }
43
 
44
    if (enc->block_align == 50) {
45
        avio_write(pb, mode30_header, sizeof(mode30_header) - 1);
46
    } else if (enc->block_align == 38) {
47
        avio_write(pb, mode20_header, sizeof(mode20_header) - 1);
48
    } else {
49
        av_log(s, AV_LOG_ERROR, "Unsupported mode\n");
50
        return AVERROR(EINVAL);
51
    }
52
    avio_flush(pb);
53
    return 0;
54
}
55
 
56
static int ilbc_write_packet(AVFormatContext *s, AVPacket *pkt)
57
{
58
    avio_write(s->pb, pkt->data, pkt->size);
59
    return 0;
60
}
61
 
62
static int ilbc_probe(AVProbeData *p)
63
{
64
    // Only check for "#!iLBC" which matches both formats
65
    if (!memcmp(p->buf, mode20_header, 6))
66
        return AVPROBE_SCORE_MAX;
67
    else
68
        return 0;
69
}
70
 
71
static int ilbc_read_header(AVFormatContext *s)
72
{
73
    AVIOContext *pb = s->pb;
74
    AVStream *st;
75
    uint8_t header[9];
76
 
77
    avio_read(pb, header, 9);
78
 
79
    st = avformat_new_stream(s, NULL);
80
    if (!st)
81
        return AVERROR(ENOMEM);
82
    st->codec->codec_id = AV_CODEC_ID_ILBC;
83
    st->codec->sample_rate = 8000;
84
    st->codec->channels = 1;
85
    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
86
    st->start_time = 0;
87
    avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
88
    if (!memcmp(header, mode20_header, sizeof(mode20_header) - 1)) {
89
        st->codec->block_align = 38;
90
        st->codec->bit_rate = 15200;
91
    } else if (!memcmp(header, mode30_header, sizeof(mode30_header) - 1)) {
92
        st->codec->block_align = 50;
93
        st->codec->bit_rate = 13333;
94
    } else {
95
        av_log(s, AV_LOG_ERROR, "Unrecognized iLBC file header\n");
96
        return AVERROR_INVALIDDATA;
97
    }
98
 
99
    return 0;
100
}
101
 
102
static int ilbc_read_packet(AVFormatContext *s,
103
                          AVPacket *pkt)
104
{
105
    AVCodecContext *enc = s->streams[0]->codec;
106
    int ret;
107
 
108
    if ((ret = av_new_packet(pkt, enc->block_align)) < 0)
109
        return ret;
110
 
111
    pkt->stream_index = 0;
112
    pkt->pos = avio_tell(s->pb);
113
    pkt->duration = enc->block_align == 38 ? 160 : 240;
114
    if ((ret = avio_read(s->pb, pkt->data, enc->block_align)) != enc->block_align) {
115
        av_free_packet(pkt);
116
        return ret < 0 ? ret : AVERROR(EIO);
117
    }
118
 
119
    return 0;
120
}
121
 
122
AVInputFormat ff_ilbc_demuxer = {
123
    .name         = "ilbc",
124
    .long_name    = NULL_IF_CONFIG_SMALL("iLBC storage"),
125
    .read_probe   = ilbc_probe,
126
    .read_header  = ilbc_read_header,
127
    .read_packet  = ilbc_read_packet,
128
    .flags        = AVFMT_GENERIC_INDEX,
129
};
130
 
131
AVOutputFormat ff_ilbc_muxer = {
132
    .name         = "ilbc",
133
    .long_name    = NULL_IF_CONFIG_SMALL("iLBC storage"),
134
    .mime_type    = "audio/iLBC",
135
    .extensions   = "lbc",
136
    .audio_codec  = AV_CODEC_ID_ILBC,
137
    .write_header = ilbc_write_header,
138
    .write_packet = ilbc_write_packet,
139
    .flags        = AVFMT_NOTIMESTAMPS,
140
};