yading@11: /* yading@11: * SoX native format muxer yading@11: * Copyright (c) 2009 Daniel Verkamp yading@11: * yading@11: * Based on libSoX sox-fmt.c yading@11: * Copyright (c) 2008 robs@users.sourceforge.net yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: /** yading@11: * @file yading@11: * SoX native format muxer yading@11: * @author Daniel Verkamp yading@11: * @see http://wiki.multimedia.cx/index.php?title=SoX_native_intermediate_format yading@11: */ yading@11: yading@11: #include "libavutil/intreadwrite.h" yading@11: #include "libavutil/intfloat.h" yading@11: #include "libavutil/dict.h" yading@11: #include "avformat.h" yading@11: #include "avio_internal.h" yading@11: #include "rawenc.h" yading@11: #include "sox.h" yading@11: yading@11: typedef struct { yading@11: int64_t header_size; yading@11: } SoXContext; yading@11: yading@11: static int sox_write_header(AVFormatContext *s) yading@11: { yading@11: SoXContext *sox = s->priv_data; yading@11: AVIOContext *pb = s->pb; yading@11: AVCodecContext *enc = s->streams[0]->codec; yading@11: AVDictionaryEntry *comment; yading@11: size_t comment_len = 0, comment_size; yading@11: yading@11: comment = av_dict_get(s->metadata, "comment", NULL, 0); yading@11: if (comment) yading@11: comment_len = strlen(comment->value); yading@11: comment_size = FFALIGN(comment_len, 8); yading@11: yading@11: sox->header_size = SOX_FIXED_HDR + comment_size; yading@11: yading@11: if (enc->codec_id == AV_CODEC_ID_PCM_S32LE) { yading@11: ffio_wfourcc(pb, ".SoX"); yading@11: avio_wl32(pb, sox->header_size); yading@11: avio_wl64(pb, 0); /* number of samples */ yading@11: avio_wl64(pb, av_double2int(enc->sample_rate)); yading@11: avio_wl32(pb, enc->channels); yading@11: avio_wl32(pb, comment_size); yading@11: } else if (enc->codec_id == AV_CODEC_ID_PCM_S32BE) { yading@11: ffio_wfourcc(pb, "XoS."); yading@11: avio_wb32(pb, sox->header_size); yading@11: avio_wb64(pb, 0); /* number of samples */ yading@11: avio_wb64(pb, av_double2int(enc->sample_rate)); yading@11: avio_wb32(pb, enc->channels); yading@11: avio_wb32(pb, comment_size); yading@11: } else { yading@11: av_log(s, AV_LOG_ERROR, "invalid codec; use pcm_s32le or pcm_s32be\n"); yading@11: return -1; yading@11: } yading@11: yading@11: if (comment_len) yading@11: avio_write(pb, comment->value, comment_len); yading@11: yading@11: ffio_fill(pb, 0, comment_size - comment_len); yading@11: yading@11: avio_flush(pb); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: static int sox_write_trailer(AVFormatContext *s) yading@11: { yading@11: SoXContext *sox = s->priv_data; yading@11: AVIOContext *pb = s->pb; yading@11: AVCodecContext *enc = s->streams[0]->codec; yading@11: yading@11: if (s->pb->seekable) { yading@11: /* update number of samples */ yading@11: int64_t file_size = avio_tell(pb); yading@11: int64_t num_samples = (file_size - sox->header_size - 4LL) >> 2LL; yading@11: avio_seek(pb, 8, SEEK_SET); yading@11: if (enc->codec_id == AV_CODEC_ID_PCM_S32LE) { yading@11: avio_wl64(pb, num_samples); yading@11: } else yading@11: avio_wb64(pb, num_samples); yading@11: avio_seek(pb, file_size, SEEK_SET); yading@11: yading@11: avio_flush(pb); yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: AVOutputFormat ff_sox_muxer = { yading@11: .name = "sox", yading@11: .long_name = NULL_IF_CONFIG_SMALL("SoX native"), yading@11: .extensions = "sox", yading@11: .priv_data_size = sizeof(SoXContext), yading@11: .audio_codec = AV_CODEC_ID_PCM_S32LE, yading@11: .video_codec = AV_CODEC_ID_NONE, yading@11: .write_header = sox_write_header, yading@11: .write_packet = ff_raw_write_packet, yading@11: .write_trailer = sox_write_trailer, yading@11: };