00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00032 #include "libavutil/intreadwrite.h"
00033 #include "libavutil/dict.h"
00034 #include "avformat.h"
00035 #include "avio_internal.h"
00036 #include "sox.h"
00037
00038 typedef struct {
00039 int64_t header_size;
00040 } SoXContext;
00041
00042 static int sox_write_header(AVFormatContext *s)
00043 {
00044 SoXContext *sox = s->priv_data;
00045 AVIOContext *pb = s->pb;
00046 AVCodecContext *enc = s->streams[0]->codec;
00047 AVDictionaryEntry *comment;
00048 size_t comment_len = 0, comment_size;
00049
00050 comment = av_dict_get(s->metadata, "comment", NULL, 0);
00051 if (comment)
00052 comment_len = strlen(comment->value);
00053 comment_size = (comment_len + 7) & ~7;
00054
00055 sox->header_size = SOX_FIXED_HDR + comment_size;
00056
00057 if (enc->codec_id == CODEC_ID_PCM_S32LE) {
00058 ffio_wfourcc(pb, ".SoX");
00059 avio_wl32(pb, sox->header_size);
00060 avio_wl64(pb, 0);
00061 avio_wl64(pb, av_dbl2int(enc->sample_rate));
00062 avio_wl32(pb, enc->channels);
00063 avio_wl32(pb, comment_size);
00064 } else if (enc->codec_id == CODEC_ID_PCM_S32BE) {
00065 ffio_wfourcc(pb, "XoS.");
00066 avio_wb32(pb, sox->header_size);
00067 avio_wb64(pb, 0);
00068 avio_wb64(pb, av_dbl2int(enc->sample_rate));
00069 avio_wb32(pb, enc->channels);
00070 avio_wb32(pb, comment_size);
00071 } else {
00072 av_log(s, AV_LOG_ERROR, "invalid codec; use pcm_s32le or pcm_s32be\n");
00073 return -1;
00074 }
00075
00076 if (comment_len)
00077 avio_write(pb, comment->value, comment_len);
00078
00079 for ( ; comment_size > comment_len; comment_len++)
00080 avio_w8(pb, 0);
00081
00082 avio_flush(pb);
00083
00084 return 0;
00085 }
00086
00087 static int sox_write_packet(AVFormatContext *s, AVPacket *pkt)
00088 {
00089 AVIOContext *pb = s->pb;
00090 avio_write(pb, pkt->data, pkt->size);
00091 return 0;
00092 }
00093
00094 static int sox_write_trailer(AVFormatContext *s)
00095 {
00096 SoXContext *sox = s->priv_data;
00097 AVIOContext *pb = s->pb;
00098 AVCodecContext *enc = s->streams[0]->codec;
00099
00100 if (s->pb->seekable) {
00101
00102 int64_t file_size = avio_tell(pb);
00103 int64_t num_samples = (file_size - sox->header_size - 4LL) >> 2LL;
00104 avio_seek(pb, 8, SEEK_SET);
00105 if (enc->codec_id == CODEC_ID_PCM_S32LE) {
00106 avio_wl64(pb, num_samples);
00107 } else
00108 avio_wb64(pb, num_samples);
00109 avio_seek(pb, file_size, SEEK_SET);
00110
00111 avio_flush(pb);
00112 }
00113
00114 return 0;
00115 }
00116
00117 AVOutputFormat ff_sox_muxer = {
00118 "sox",
00119 NULL_IF_CONFIG_SMALL("SoX native format"),
00120 NULL,
00121 "sox",
00122 sizeof(SoXContext),
00123 CODEC_ID_PCM_S32LE,
00124 CODEC_ID_NONE,
00125 sox_write_header,
00126 sox_write_packet,
00127 sox_write_trailer,
00128 };