]> git.sesse.net Git - ffmpeg/blob - libavformat/soxenc.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavformat / soxenc.c
1 /*
2  * SoX native format muxer
3  * Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu>
4  *
5  * Based on libSoX sox-fmt.c
6  * Copyright (c) 2008 robs@users.sourceforge.net
7  *
8  * This file is part of FFmpeg.
9  *
10  * FFmpeg is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * FFmpeg is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with FFmpeg; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  */
24
25 /**
26  * SoX native format muxer
27  * @file
28  * @author Daniel Verkamp
29  * @sa http://wiki.multimedia.cx/index.php?title=SoX_native_intermediate_format
30  */
31
32 #include "libavutil/intreadwrite.h"
33 #include "libavutil/dict.h"
34 #include "avformat.h"
35 #include "avio_internal.h"
36 #include "sox.h"
37
38 typedef struct {
39     int64_t header_size;
40 } SoXContext;
41
42 static int sox_write_header(AVFormatContext *s)
43 {
44     SoXContext *sox = s->priv_data;
45     AVIOContext *pb = s->pb;
46     AVCodecContext *enc = s->streams[0]->codec;
47     AVDictionaryEntry *comment;
48     size_t comment_len = 0, comment_size;
49
50     comment = av_dict_get(s->metadata, "comment", NULL, 0);
51     if (comment)
52         comment_len = strlen(comment->value);
53     comment_size = (comment_len + 7) & ~7;
54
55     sox->header_size = SOX_FIXED_HDR + comment_size;
56
57     if (enc->codec_id == CODEC_ID_PCM_S32LE) {
58         ffio_wfourcc(pb, ".SoX");
59         avio_wl32(pb, sox->header_size);
60         avio_wl64(pb, 0); /* number of samples */
61         avio_wl64(pb, av_dbl2int(enc->sample_rate));
62         avio_wl32(pb, enc->channels);
63         avio_wl32(pb, comment_size);
64     } else if (enc->codec_id == CODEC_ID_PCM_S32BE) {
65         ffio_wfourcc(pb, "XoS.");
66         avio_wb32(pb, sox->header_size);
67         avio_wb64(pb, 0); /* number of samples */
68         avio_wb64(pb, av_dbl2int(enc->sample_rate));
69         avio_wb32(pb, enc->channels);
70         avio_wb32(pb, comment_size);
71     } else {
72         av_log(s, AV_LOG_ERROR, "invalid codec; use pcm_s32le or pcm_s32be\n");
73         return -1;
74     }
75
76     if (comment_len)
77         avio_write(pb, comment->value, comment_len);
78
79     for ( ; comment_size > comment_len; comment_len++)
80         avio_w8(pb, 0);
81
82     avio_flush(pb);
83
84     return 0;
85 }
86
87 static int sox_write_packet(AVFormatContext *s, AVPacket *pkt)
88 {
89     AVIOContext *pb = s->pb;
90     avio_write(pb, pkt->data, pkt->size);
91     return 0;
92 }
93
94 static int sox_write_trailer(AVFormatContext *s)
95 {
96     SoXContext *sox = s->priv_data;
97     AVIOContext *pb = s->pb;
98     AVCodecContext *enc = s->streams[0]->codec;
99
100     if (s->pb->seekable) {
101         /* update number of samples */
102         int64_t file_size = avio_tell(pb);
103         int64_t num_samples = (file_size - sox->header_size - 4LL) >> 2LL;
104         avio_seek(pb, 8, SEEK_SET);
105         if (enc->codec_id == CODEC_ID_PCM_S32LE) {
106             avio_wl64(pb, num_samples);
107         } else
108             avio_wb64(pb, num_samples);
109         avio_seek(pb, file_size, SEEK_SET);
110
111         avio_flush(pb);
112     }
113
114     return 0;
115 }
116
117 AVOutputFormat ff_sox_muxer = {
118     "sox",
119     NULL_IF_CONFIG_SMALL("SoX native format"),
120     NULL,
121     "sox",
122     sizeof(SoXContext),
123     CODEC_ID_PCM_S32LE,
124     CODEC_ID_NONE,
125     sox_write_header,
126     sox_write_packet,
127     sox_write_trailer,
128 };