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