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 "avformat.h" 34#include "sox.h" 35 36typedef struct { 37 int64_t header_size; 38} SoXContext; 39 40static int sox_write_header(AVFormatContext *s) 41{ 42 SoXContext *sox = s->priv_data; 43 ByteIOContext *pb = s->pb; 44 AVCodecContext *enc = s->streams[0]->codec; 45 AVMetadataTag *comment; 46 size_t comment_len = 0, comment_size; 47 48 comment = av_metadata_get(s->metadata, "comment", NULL, 0); 49 if (comment) 50 comment_len = strlen(comment->value); 51 comment_size = (comment_len + 7) & ~7; 52 53 sox->header_size = SOX_FIXED_HDR + comment_size; 54 55 if (enc->codec_id == CODEC_ID_PCM_S32LE) { 56 put_tag(pb, ".SoX"); 57 put_le32(pb, sox->header_size); 58 put_le64(pb, 0); /* number of samples */ 59 put_le64(pb, av_dbl2int(enc->sample_rate)); 60 put_le32(pb, enc->channels); 61 put_le32(pb, comment_size); 62 } else if (enc->codec_id == CODEC_ID_PCM_S32BE) { 63 put_tag(pb, "XoS."); 64 put_be32(pb, sox->header_size); 65 put_be64(pb, 0); /* number of samples */ 66 put_be64(pb, av_dbl2int(enc->sample_rate)); 67 put_be32(pb, enc->channels); 68 put_be32(pb, comment_size); 69 } else { 70 av_log(s, AV_LOG_ERROR, "invalid codec; use pcm_s32le or pcm_s32be\n"); 71 return -1; 72 } 73 74 if (comment_len) 75 put_buffer(pb, comment->value, comment_len); 76 77 for ( ; comment_size > comment_len; comment_len++) 78 put_byte(pb, 0); 79 80 put_flush_packet(pb); 81 82 return 0; 83} 84 85static int sox_write_packet(AVFormatContext *s, AVPacket *pkt) 86{ 87 ByteIOContext *pb = s->pb; 88 put_buffer(pb, pkt->data, pkt->size); 89 return 0; 90} 91 92static int sox_write_trailer(AVFormatContext *s) 93{ 94 SoXContext *sox = s->priv_data; 95 ByteIOContext *pb = s->pb; 96 AVCodecContext *enc = s->streams[0]->codec; 97 98 if (!url_is_streamed(s->pb)) { 99 /* update number of samples */ 100 int64_t file_size = url_ftell(pb); 101 int64_t num_samples = (file_size - sox->header_size - 4LL) >> 2LL; 102 url_fseek(pb, 8, SEEK_SET); 103 if (enc->codec_id == CODEC_ID_PCM_S32LE) { 104 put_le64(pb, num_samples); 105 } else 106 put_be64(pb, num_samples); 107 url_fseek(pb, file_size, SEEK_SET); 108 109 put_flush_packet(pb); 110 } 111 112 return 0; 113} 114 115AVOutputFormat sox_muxer = { 116 "sox", 117 NULL_IF_CONFIG_SMALL("SoX native format"), 118 NULL, 119 "sox", 120 sizeof(SoXContext), 121 CODEC_ID_PCM_S32LE, 122 CODEC_ID_NONE, 123 sox_write_header, 124 sox_write_packet, 125 sox_write_trailer, 126}; 127