2 * Brute Force & Ignorance (BFI) demuxer
3 * Copyright (c) 2008 Sisir Koppaka
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 * @brief Brute Force & Ignorance (.bfi) file demuxer
25 * @author Sisir Koppaka ( sisir.koppaka at gmail dot com )
26 * @see http://wiki.multimedia.cx/index.php?title=BFI
29 #include "libavutil/channel_layout.h"
30 #include "libavutil/intreadwrite.h"
35 typedef struct BFIContext
{
43 static int bfi_probe(const AVProbeData
* p
)
45 /* Check file header */
46 if (AV_RL32(p
->buf
) == MKTAG('B', 'F', '&', 'I'))
47 return AVPROBE_SCORE_MAX
;
52 static int bfi_read_header(AVFormatContext
* s
)
54 BFIContext
*bfi
= s
->priv_data
;
55 AVIOContext
*pb
= s
->pb
;
58 int ret
, fps
, chunk_header
;
60 /* Initialize the video codec... */
61 vstream
= avformat_new_stream(s
, NULL
);
63 return AVERROR(ENOMEM
);
65 /* Initialize the audio codec... */
66 astream
= avformat_new_stream(s
, NULL
);
68 return AVERROR(ENOMEM
);
70 /* Set the total number of frames. */
72 chunk_header
= avio_rl32(pb
);
74 return AVERROR_INVALIDDATA
;
76 bfi
->nframes
= avio_rl32(pb
);
78 return AVERROR_INVALIDDATA
;
84 vstream
->codecpar
->width
= avio_rl32(pb
);
85 vstream
->codecpar
->height
= avio_rl32(pb
);
87 /*Load the palette to extradata */
89 ret
= ff_get_extradata(s
, vstream
->codecpar
, pb
, 768);
93 astream
->codecpar
->sample_rate
= avio_rl32(pb
);
94 if (astream
->codecpar
->sample_rate
<= 0) {
95 av_log(s
, AV_LOG_ERROR
, "Invalid sample rate %d\n", astream
->codecpar
->sample_rate
);
96 return AVERROR_INVALIDDATA
;
99 /* Set up the video codec... */
100 avpriv_set_pts_info(vstream
, 32, 1, fps
);
101 vstream
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
102 vstream
->codecpar
->codec_id
= AV_CODEC_ID_BFI
;
103 vstream
->codecpar
->format
= AV_PIX_FMT_PAL8
;
105 vstream
->duration
= bfi
->nframes
;
107 /* Set up the audio codec now... */
108 astream
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
109 astream
->codecpar
->codec_id
= AV_CODEC_ID_PCM_U8
;
110 astream
->codecpar
->ch_layout
= (AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
;
111 astream
->codecpar
->bits_per_coded_sample
= 8;
112 astream
->codecpar
->bit_rate
=
113 (int64_t)astream
->codecpar
->sample_rate
* astream
->codecpar
->bits_per_coded_sample
;
114 avio_seek(pb
, chunk_header
- 3, SEEK_SET
);
115 avpriv_set_pts_info(astream
, 64, 1, astream
->codecpar
->sample_rate
);
120 static int bfi_read_packet(AVFormatContext
* s
, AVPacket
* pkt
)
122 BFIContext
*bfi
= s
->priv_data
;
123 AVIOContext
*pb
= s
->pb
;
124 int ret
, audio_offset
, video_offset
, chunk_size
, audio_size
= 0;
125 if (bfi
->nframes
== 0 || avio_feof(pb
)) {
129 /* If all previous chunks were completely read, then find a new one... */
132 while(state
!= MKTAG('S','A','V','I')){
134 return AVERROR_INVALIDDATA
;
135 state
= 256*state
+ avio_r8(pb
);
137 /* Now that the chunk's location is confirmed, we proceed... */
138 chunk_size
= avio_rl32(pb
);
140 audio_offset
= avio_rl32(pb
);
142 video_offset
= avio_rl32(pb
);
143 if (audio_offset
< 0 || video_offset
< audio_offset
|| chunk_size
< video_offset
) {
144 av_log(s
, AV_LOG_ERROR
, "Invalid audio/video offsets or chunk size\n");
145 return AVERROR_INVALIDDATA
;
147 audio_size
= video_offset
- audio_offset
;
148 bfi
->video_size
= chunk_size
- video_offset
;
150 //Tossing an audio packet at the audio decoder.
151 ret
= av_get_packet(pb
, pkt
, audio_size
);
155 pkt
->pts
= bfi
->audio_frame
;
156 bfi
->audio_frame
+= ret
;
157 } else if (bfi
->video_size
> 0) {
159 //Tossing a video packet at the video decoder.
160 ret
= av_get_packet(pb
, pkt
, bfi
->video_size
);
164 pkt
->pts
= bfi
->video_frame
;
165 bfi
->video_frame
+= ret
/ bfi
->video_size
;
167 /* One less frame to read. A cursory decrement. */
170 /* Empty video packet */
171 ret
= AVERROR(EAGAIN
);
174 bfi
->avflag
= !bfi
->avflag
;
175 pkt
->stream_index
= bfi
->avflag
;
179 const FFInputFormat ff_bfi_demuxer
= {
181 .p
.long_name
= NULL_IF_CONFIG_SMALL("Brute Force & Ignorance"),
182 .priv_data_size
= sizeof(BFIContext
),
183 .read_probe
= bfi_probe
,
184 .read_header
= bfi_read_header
,
185 .read_packet
= bfi_read_packet
,