2 * Delphine Software International CIN File Demuxer
3 * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * Delphine Software International CIN file demuxer
27 #include "libavutil/channel_layout.h"
28 #include "libavutil/intreadwrite.h"
32 #include "avio_internal.h"
35 typedef struct CinFileHeader
{
37 int video_frame_width
;
38 int video_frame_height
;
45 typedef struct CinFrameHeader
{
53 typedef struct CinDemuxContext
{
54 int audio_stream_index
;
55 int video_stream_index
;
56 CinFileHeader file_header
;
57 int64_t audio_stream_pts
;
58 int64_t video_stream_pts
;
59 CinFrameHeader frame_header
;
60 int audio_buffer_size
;
64 static int cin_probe(const AVProbeData
*p
)
66 /* header starts with this special marker */
67 if (AV_RL32(&p
->buf
[0]) != 0x55AA0000)
70 /* for accuracy, check some header field values */
71 if (AV_RL32(&p
->buf
[12]) != 22050 || p
->buf
[16] != 16 || p
->buf
[17] != 0)
74 return AVPROBE_SCORE_MAX
;
77 static int cin_read_file_header(CinDemuxContext
*cin
, AVIOContext
*pb
) {
78 CinFileHeader
*hdr
= &cin
->file_header
;
80 if (avio_rl32(pb
) != 0x55AA0000)
81 return AVERROR_INVALIDDATA
;
83 hdr
->video_frame_size
= avio_rl32(pb
);
84 hdr
->video_frame_width
= avio_rl16(pb
);
85 hdr
->video_frame_height
= avio_rl16(pb
);
86 hdr
->audio_frequency
= avio_rl32(pb
);
87 hdr
->audio_bits
= avio_r8(pb
);
88 hdr
->audio_stereo
= avio_r8(pb
);
89 hdr
->audio_frame_size
= avio_rl16(pb
);
91 if (hdr
->audio_frequency
!= 22050 || hdr
->audio_bits
!= 16 || hdr
->audio_stereo
!= 0)
92 return AVERROR_INVALIDDATA
;
97 static int cin_read_header(AVFormatContext
*s
)
100 CinDemuxContext
*cin
= s
->priv_data
;
101 CinFileHeader
*hdr
= &cin
->file_header
;
102 AVIOContext
*pb
= s
->pb
;
105 rc
= cin_read_file_header(cin
, pb
);
109 cin
->video_stream_pts
= 0;
110 cin
->audio_stream_pts
= 0;
111 cin
->audio_buffer_size
= 0;
113 /* initialize the video decoder stream */
114 st
= avformat_new_stream(s
, NULL
);
116 return AVERROR(ENOMEM
);
118 avpriv_set_pts_info(st
, 32, 1, 12);
119 cin
->video_stream_index
= st
->index
;
120 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
121 st
->codecpar
->codec_id
= AV_CODEC_ID_DSICINVIDEO
;
122 st
->codecpar
->codec_tag
= 0; /* no fourcc */
123 st
->codecpar
->width
= hdr
->video_frame_width
;
124 st
->codecpar
->height
= hdr
->video_frame_height
;
126 /* initialize the audio decoder stream */
127 st
= avformat_new_stream(s
, NULL
);
129 return AVERROR(ENOMEM
);
131 avpriv_set_pts_info(st
, 32, 1, 22050);
132 cin
->audio_stream_index
= st
->index
;
133 st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
134 st
->codecpar
->codec_id
= AV_CODEC_ID_DSICINAUDIO
;
135 st
->codecpar
->codec_tag
= 0; /* no tag */
136 st
->codecpar
->ch_layout
= (AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
;
137 st
->codecpar
->sample_rate
= 22050;
138 st
->codecpar
->bits_per_coded_sample
= 8;
139 st
->codecpar
->bit_rate
= st
->codecpar
->sample_rate
*
140 st
->codecpar
->bits_per_coded_sample
*
141 st
->codecpar
->ch_layout
.nb_channels
;
146 static int cin_read_frame_header(CinDemuxContext
*cin
, AVIOContext
*pb
) {
147 CinFrameHeader
*hdr
= &cin
->frame_header
;
149 hdr
->video_frame_type
= avio_r8(pb
);
150 hdr
->audio_frame_type
= avio_r8(pb
);
151 hdr
->pal_colors_count
= avio_rl16(pb
);
152 hdr
->video_frame_size
= avio_rl32(pb
);
153 hdr
->audio_frame_size
= avio_rl32(pb
);
155 if (avio_feof(pb
) || pb
->error
)
156 return pb
->error
? pb
->error
: AVERROR_INVALIDDATA
;
158 if (avio_rl32(pb
) != 0xAA55AA55)
159 return AVERROR_INVALIDDATA
;
160 if (hdr
->video_frame_size
< 0 || hdr
->audio_frame_size
< 0)
161 return AVERROR_INVALIDDATA
;
166 static int cin_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
168 CinDemuxContext
*cin
= s
->priv_data
;
169 AVIOContext
*pb
= s
->pb
;
170 CinFrameHeader
*hdr
= &cin
->frame_header
;
171 int rc
, palette_type
;
175 if (cin
->audio_buffer_size
== 0) {
176 rc
= cin_read_frame_header(cin
, pb
);
180 if ((int16_t)hdr
->pal_colors_count
< 0) {
181 hdr
->pal_colors_count
= -(int16_t)hdr
->pal_colors_count
;
187 /* palette and video packet */
188 pkt_size
= (palette_type
+ 3LL) * hdr
->pal_colors_count
+ hdr
->video_frame_size
;
189 if (pkt_size
+ 4 > INT_MAX
)
190 return AVERROR_INVALIDDATA
;
192 pkt_size
= ffio_limit(pb
, pkt_size
);
194 ret
= av_new_packet(pkt
, 4 + pkt_size
);
198 pkt
->stream_index
= cin
->video_stream_index
;
199 pkt
->pts
= cin
->video_stream_pts
++;
201 pkt
->data
[0] = palette_type
;
202 pkt
->data
[1] = hdr
->pal_colors_count
& 0xFF;
203 pkt
->data
[2] = hdr
->pal_colors_count
>> 8;
204 pkt
->data
[3] = hdr
->video_frame_type
;
206 ret
= avio_read(pb
, &pkt
->data
[4], pkt_size
);
211 av_shrink_packet(pkt
, 4 + ret
);
213 /* sound buffer will be processed on next read_packet() call */
214 cin
->audio_buffer_size
= hdr
->audio_frame_size
;
219 ret
= av_get_packet(pb
, pkt
, cin
->audio_buffer_size
);
223 pkt
->stream_index
= cin
->audio_stream_index
;
224 pkt
->pts
= cin
->audio_stream_pts
;
225 pkt
->duration
= cin
->audio_buffer_size
- (pkt
->pts
== 0);
226 cin
->audio_stream_pts
+= pkt
->duration
;
227 cin
->audio_buffer_size
= 0;
231 const FFInputFormat ff_dsicin_demuxer
= {
233 .p
.long_name
= NULL_IF_CONFIG_SMALL("Delphine Software International CIN"),
234 .priv_data_size
= sizeof(CinDemuxContext
),
235 .read_probe
= cin_probe
,
236 .read_header
= cin_read_header
,
237 .read_packet
= cin_read_packet
,