Browse code

Bitmap Brothers JV demuxer

Signed-off-by: Ronald S. Bultje <rsbultje@gmail.com>

Peter Ross authored on 2011/03/10 21:29:22
Showing 4 changed files
... ...
@@ -110,6 +110,7 @@ OBJS-$(CONFIG_ISS_DEMUXER)               += iss.o
110 110
 OBJS-$(CONFIG_IV8_DEMUXER)               += iv8.o
111 111
 OBJS-$(CONFIG_IVF_DEMUXER)               += ivfdec.o riff.o
112 112
 OBJS-$(CONFIG_IVF_MUXER)                 += ivfenc.o
113
+OBJS-$(CONFIG_JV_DEMUXER)                += jvdec.o
113 114
 OBJS-$(CONFIG_LMLM4_DEMUXER)             += lmlm4.o
114 115
 OBJS-$(CONFIG_LXF_DEMUXER)               += lxfdec.o
115 116
 OBJS-$(CONFIG_M4V_DEMUXER)               += m4vdec.o rawdec.o
... ...
@@ -110,6 +110,7 @@ void av_register_all(void)
110 110
     REGISTER_DEMUXER  (ISS, iss);
111 111
     REGISTER_DEMUXER  (IV8, iv8);
112 112
     REGISTER_MUXDEMUX (IVF, ivf);
113
+    REGISTER_DEMUXER  (JV, jv);
113 114
     REGISTER_DEMUXER  (LMLM4, lmlm4);
114 115
     REGISTER_DEMUXER  (LXF, lxf);
115 116
     REGISTER_MUXDEMUX (M4V, m4v);
116 117
new file mode 100644
... ...
@@ -0,0 +1,221 @@
0
+/*
1
+ * Bitmap Brothers JV demuxer
2
+ * Copyright (c) 2005, 2011 Peter Ross <pross@xvid.org>
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * Bitmap Brothers JV demuxer
24
+ * @author Peter Ross <pross@xvid.org>
25
+ */
26
+
27
+#include "libavutil/intreadwrite.h"
28
+#include "avformat.h"
29
+
30
+typedef struct {
31
+    int audio_size;    /** audio packet size (bytes) */
32
+    int video_size;    /** video packet size (bytes) */
33
+    int palette;       /** frame contains palette change */
34
+    int video_type;    /** per-frame video compression type */
35
+} JVFrame;
36
+
37
+typedef struct {
38
+    JVFrame *frames;
39
+    enum {
40
+        JV_AUDIO = 0,
41
+        JV_VIDEO,
42
+        JV_PADDING
43
+    } state;
44
+    int64_t pts;
45
+} JVDemuxContext;
46
+
47
+#define MAGIC " Compression by John M Phillips Copyright (C) 1995 The Bitmap Brothers Ltd."
48
+
49
+static int read_probe(AVProbeData *pd)
50
+{
51
+    if (pd->buf[0] == 'J' && pd->buf[1] == 'V' &&
52
+        !memcmp(pd->buf + 4, MAGIC, FFMIN(strlen(MAGIC), pd->buf_size - 4)))
53
+        return AVPROBE_SCORE_MAX;
54
+    return 0;
55
+}
56
+
57
+static int read_header(AVFormatContext *s,
58
+                       AVFormatParameters *ap)
59
+{
60
+    JVDemuxContext *jv = s->priv_data;
61
+    AVIOContext *pb = s->pb;
62
+    AVStream *vst, *ast;
63
+    int64_t audio_pts = 0;
64
+    int64_t offset;
65
+    int i;
66
+
67
+    avio_skip(pb, 80);
68
+
69
+    ast = av_new_stream(s, 0);
70
+    vst = av_new_stream(s, 1);
71
+    if (!ast || !vst)
72
+        return AVERROR(ENOMEM);
73
+
74
+    vst->codec->codec_type  = CODEC_TYPE_VIDEO;
75
+    vst->codec->codec_id    = CODEC_ID_JV;
76
+    vst->codec->codec_tag   = 0; /* no fourcc */
77
+    vst->codec->width       = avio_rl16(pb);
78
+    vst->codec->height      = avio_rl16(pb);
79
+    vst->nb_frames          =
80
+    ast->nb_index_entries   = avio_rl16(pb);
81
+    av_set_pts_info(vst, 64, avio_rl16(pb), 1000);
82
+
83
+    avio_skip(pb, 4);
84
+
85
+    ast->codec->codec_type  = CODEC_TYPE_AUDIO;
86
+    ast->codec->codec_id    = CODEC_ID_PCM_U8;
87
+    ast->codec->codec_tag   = 0; /* no fourcc */
88
+    ast->codec->sample_rate = avio_rl16(pb);
89
+    ast->codec->channels    = 1;
90
+    av_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
91
+
92
+    avio_skip(pb, 10);
93
+
94
+    ast->index_entries = av_malloc(ast->nb_index_entries * sizeof(*ast->index_entries));
95
+    if (!ast->index_entries)
96
+        return AVERROR(ENOMEM);
97
+
98
+    jv->frames = av_malloc(ast->nb_index_entries * sizeof(JVFrame));
99
+    if (!jv->frames)
100
+        return AVERROR(ENOMEM);
101
+
102
+    offset = 0x68 + ast->nb_index_entries * 16;
103
+    for(i = 0; i < ast->nb_index_entries; i++) {
104
+        AVIndexEntry *e   = ast->index_entries + i;
105
+        JVFrame      *jvf = jv->frames + i;
106
+
107
+        /* total frame size including audio, video, palette data and padding */
108
+        e->size         = avio_rl32(pb);
109
+        e->timestamp    = i;
110
+        e->pos          = offset;
111
+        offset         += e->size;
112
+
113
+        jvf->audio_size = avio_rl32(pb);
114
+        jvf->video_size = avio_rl32(pb);
115
+        jvf->palette    = avio_r8(pb);
116
+        if (avio_r8(pb))
117
+             av_log(s, AV_LOG_WARNING, "unsupported audio codec\n");
118
+        jvf->video_type = avio_r8(pb);
119
+        avio_skip(pb, 1);
120
+
121
+        e->timestamp = jvf->audio_size ? audio_pts : AV_NOPTS_VALUE;
122
+        audio_pts += jvf->audio_size;
123
+
124
+        e->flags = jvf->video_type != 1 ? AVINDEX_KEYFRAME : 0;
125
+    }
126
+
127
+    jv->state = JV_AUDIO;
128
+    return 0;
129
+}
130
+
131
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
132
+{
133
+    JVDemuxContext *jv = s->priv_data;
134
+    AVIOContext *pb = s->pb;
135
+    AVStream *ast = s->streams[0];
136
+
137
+    while (!url_feof(s->pb) && jv->pts < ast->nb_index_entries) {
138
+        const AVIndexEntry *e   = ast->index_entries + jv->pts;
139
+        const JVFrame      *jvf = jv->frames + jv->pts;
140
+
141
+        switch(jv->state) {
142
+        case JV_AUDIO:
143
+            jv->state++;
144
+            if (jvf->audio_size ) {
145
+                if (av_get_packet(s->pb, pkt, jvf->audio_size) < 0)
146
+                    return AVERROR(ENOMEM);
147
+                pkt->stream_index = 0;
148
+                pkt->pts          = e->timestamp;
149
+                pkt->flags       |= PKT_FLAG_KEY;
150
+                return 0;
151
+            }
152
+        case JV_VIDEO:
153
+            jv->state++;
154
+            if (jvf->video_size || jvf->palette) {
155
+                int size = jvf->video_size + (jvf->palette ? 768 : 0);
156
+                if (av_new_packet(pkt, size + 5))
157
+                    return AVERROR(ENOMEM);
158
+
159
+                AV_WL32(pkt->data, jvf->video_size);
160
+                pkt->data[4]      = jvf->video_type;
161
+                if (avio_read(pb, pkt->data + 5, size) < 0)
162
+                    return AVERROR(EIO);
163
+
164
+                pkt->size         = size + 5;
165
+                pkt->stream_index = 1;
166
+                pkt->pts          = jv->pts;
167
+                if (jvf->video_type != 1)
168
+                    pkt->flags |= PKT_FLAG_KEY;
169
+                return 0;
170
+            }
171
+        case JV_PADDING:
172
+            avio_skip(pb, FFMAX(e->size - jvf->audio_size - jvf->video_size
173
+                                        - (jvf->palette ? 768 : 0), 0));
174
+            jv->state = JV_AUDIO;
175
+            jv->pts++;
176
+        }
177
+    }
178
+
179
+    return AVERROR(EIO);
180
+}
181
+
182
+static int read_seek(AVFormatContext *s, int stream_index,
183
+                     int64_t ts, int flags)
184
+{
185
+    JVDemuxContext *jv = s->priv_data;
186
+    AVStream *ast = s->streams[0];
187
+    int i;
188
+
189
+    if (flags & (AVSEEK_FLAG_BYTE|AVSEEK_FLAG_FRAME))
190
+        return AVERROR_NOTSUPP;
191
+
192
+    switch(stream_index) {
193
+    case 0:
194
+        i = av_index_search_timestamp(ast, ts, flags);
195
+        break;
196
+    case 1:
197
+        i = ts;
198
+        break;
199
+    default:
200
+        return 0;
201
+    }
202
+
203
+    if (i < 0 || i >= ast->nb_index_entries)
204
+        return 0;
205
+
206
+    jv->state = JV_AUDIO;
207
+    jv->pts   = i;
208
+    avio_seek(s->pb, ast->index_entries[i].pos, SEEK_SET);
209
+    return 0;
210
+}
211
+
212
+AVInputFormat ff_jv_demuxer = {
213
+    .name           = "jv",
214
+    .long_name      = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV"),
215
+    .priv_data_size = sizeof(JVDemuxContext),
216
+    .read_probe     = read_probe,
217
+    .read_header    = read_header,
218
+    .read_packet    = read_packet,
219
+    .read_seek      = read_seek,
220
+};
... ...
@@ -24,7 +24,7 @@
24 24
 #include "libavutil/avutil.h"
25 25
 
26 26
 #define LIBAVFORMAT_VERSION_MAJOR 52
27
-#define LIBAVFORMAT_VERSION_MINOR 102
27
+#define LIBAVFORMAT_VERSION_MINOR 103
28 28
 #define LIBAVFORMAT_VERSION_MICRO  0
29 29
 
30 30
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \