1 /*
2  * RSO muxer
3  * Copyright (c) 2001 Fabrice Bellard (original AU code)
4  * Copyright (c) 2010 Rafael Carre
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "avformat.h"
24 #include "internal.h"
25 #include "riff.h"
26 #include "rso.h"
27 
rso_write_header(AVFormatContext * s)28 static int rso_write_header(AVFormatContext *s)
29 {
30     AVIOContext  *pb  = s->pb;
31     AVCodecContext *enc = s->streams[0]->codec;
32 
33     if (!enc->codec_tag)
34         return AVERROR_INVALIDDATA;
35 
36     if (enc->channels != 1) {
37         av_log(s, AV_LOG_ERROR, "RSO only supports mono\n");
38         return AVERROR_INVALIDDATA;
39     }
40 
41     if (!s->pb->seekable) {
42         av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
43         return AVERROR_INVALIDDATA;
44     }
45 
46     /* XXX: find legal sample rates (if any) */
47     if (enc->sample_rate >= 1u<<16) {
48         av_log(s, AV_LOG_ERROR, "Sample rate must be < 65536\n");
49         return AVERROR_INVALIDDATA;
50     }
51 
52     if (enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
53         av_log(s, AV_LOG_ERROR, "ADPCM in RSO not implemented\n");
54         return AVERROR_PATCHWELCOME;
55     }
56 
57     /* format header */
58     avio_wb16(pb, enc->codec_tag);   /* codec ID */
59     avio_wb16(pb, 0);                /* data size, will be written at EOF */
60     avio_wb16(pb, enc->sample_rate);
61     avio_wb16(pb, 0x0000);           /* play mode ? (0x0000 = don't loop) */
62 
63     avio_flush(pb);
64 
65     return 0;
66 }
67 
rso_write_packet(AVFormatContext * s,AVPacket * pkt)68 static int rso_write_packet(AVFormatContext *s, AVPacket *pkt)
69 {
70     avio_write(s->pb, pkt->data, pkt->size);
71     return 0;
72 }
73 
rso_write_trailer(AVFormatContext * s)74 static int rso_write_trailer(AVFormatContext *s)
75 {
76     AVIOContext *pb = s->pb;
77     int64_t file_size;
78     uint16_t coded_file_size;
79 
80     file_size = avio_tell(pb);
81 
82     if (file_size < 0)
83         return file_size;
84 
85     if (file_size > 0xffff + RSO_HEADER_SIZE) {
86         av_log(s, AV_LOG_WARNING,
87                "Output file is too big (%"PRId64" bytes >= 64kB)\n", file_size);
88         coded_file_size = 0xffff;
89     } else {
90         coded_file_size = file_size - RSO_HEADER_SIZE;
91     }
92 
93     /* update file size */
94     avio_seek(pb, 2, SEEK_SET);
95     avio_wb16(pb, coded_file_size);
96     avio_seek(pb, file_size, SEEK_SET);
97 
98     return 0;
99 }
100 
101 AVOutputFormat ff_rso_muxer = {
102 	.name           =   "rso",
103     .long_name      =   NULL_IF_CONFIG_SMALL("Lego Mindstorms RSO"),
104     .extensions     =   "rso",
105     .audio_codec    =   AV_CODEC_ID_PCM_U8,
106     .video_codec    =   AV_CODEC_ID_NONE,
107     .write_header   =   rso_write_header,
108     .write_packet   =   rso_write_packet,
109     .write_trailer  =   rso_write_trailer,
110     .codec_tag      =   (const AVCodecTag* const []){ff_codec_rso_tags, 0},
111     .flags          =   AVFMT_NOTIMESTAMPS,
112 };
113