Libav
|
00001 /* 00002 * SoX native format muxer 00003 * Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu> 00004 * 00005 * Based on libSoX sox-fmt.c 00006 * Copyright (c) 2008 robs@users.sourceforge.net 00007 * 00008 * This file is part of FFmpeg. 00009 * 00010 * FFmpeg is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * FFmpeg is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with FFmpeg; if not, write to the Free Software 00022 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00023 */ 00024 00032 #include "libavutil/intreadwrite.h" 00033 #include "avformat.h" 00034 #include "sox.h" 00035 00036 typedef struct { 00037 int64_t header_size; 00038 } SoXContext; 00039 00040 static int sox_write_header(AVFormatContext *s) 00041 { 00042 SoXContext *sox = s->priv_data; 00043 ByteIOContext *pb = s->pb; 00044 AVCodecContext *enc = s->streams[0]->codec; 00045 AVMetadataTag *comment; 00046 size_t comment_len = 0, comment_size; 00047 00048 comment = av_metadata_get(s->metadata, "comment", NULL, 0); 00049 if (comment) 00050 comment_len = strlen(comment->value); 00051 comment_size = (comment_len + 7) & ~7; 00052 00053 sox->header_size = SOX_FIXED_HDR + comment_size; 00054 00055 if (enc->codec_id == CODEC_ID_PCM_S32LE) { 00056 put_tag(pb, ".SoX"); 00057 put_le32(pb, sox->header_size); 00058 put_le64(pb, 0); /* number of samples */ 00059 put_le64(pb, av_dbl2int(enc->sample_rate)); 00060 put_le32(pb, enc->channels); 00061 put_le32(pb, comment_size); 00062 } else if (enc->codec_id == CODEC_ID_PCM_S32BE) { 00063 put_tag(pb, "XoS."); 00064 put_be32(pb, sox->header_size); 00065 put_be64(pb, 0); /* number of samples */ 00066 put_be64(pb, av_dbl2int(enc->sample_rate)); 00067 put_be32(pb, enc->channels); 00068 put_be32(pb, comment_size); 00069 } else { 00070 av_log(s, AV_LOG_ERROR, "invalid codec; use pcm_s32le or pcm_s32be\n"); 00071 return -1; 00072 } 00073 00074 if (comment_len) 00075 put_buffer(pb, comment->value, comment_len); 00076 00077 for ( ; comment_size > comment_len; comment_len++) 00078 put_byte(pb, 0); 00079 00080 put_flush_packet(pb); 00081 00082 return 0; 00083 } 00084 00085 static int sox_write_packet(AVFormatContext *s, AVPacket *pkt) 00086 { 00087 ByteIOContext *pb = s->pb; 00088 put_buffer(pb, pkt->data, pkt->size); 00089 return 0; 00090 } 00091 00092 static int sox_write_trailer(AVFormatContext *s) 00093 { 00094 SoXContext *sox = s->priv_data; 00095 ByteIOContext *pb = s->pb; 00096 AVCodecContext *enc = s->streams[0]->codec; 00097 00098 if (!url_is_streamed(s->pb)) { 00099 /* update number of samples */ 00100 int64_t file_size = url_ftell(pb); 00101 int64_t num_samples = (file_size - sox->header_size - 4LL) >> 2LL; 00102 url_fseek(pb, 8, SEEK_SET); 00103 if (enc->codec_id == CODEC_ID_PCM_S32LE) { 00104 put_le64(pb, num_samples); 00105 } else 00106 put_be64(pb, num_samples); 00107 url_fseek(pb, file_size, SEEK_SET); 00108 00109 put_flush_packet(pb); 00110 } 00111 00112 return 0; 00113 } 00114 00115 AVOutputFormat sox_muxer = { 00116 "sox", 00117 NULL_IF_CONFIG_SMALL("SoX native format"), 00118 NULL, 00119 "sox", 00120 sizeof(SoXContext), 00121 CODEC_ID_PCM_S32LE, 00122 CODEC_ID_NONE, 00123 sox_write_header, 00124 sox_write_packet, 00125 sox_write_trailer, 00126 };