Revision 148bcae9

View differences:

doc/general.texi
241 241
@item Westwood Studios VQA      @tab   @tab X
242 242
    @tab Multimedia format used in Westwood Studios games.
243 243
@item YUV4MPEG pipe             @tab X @tab X
244
@item Psygnosis YOP             @tab   @tab X
244 245
@end multitable
245 246

  
246 247
@code{X} means that encoding (resp. decoding) is supported.
......
490 491
@item Winnov WNV1            @tab     @tab  X
491 492
@item WMV7                   @tab  X  @tab  X
492 493
@item YAMAHA SMAF            @tab  X  @tab  X
494
@item Psygnosis YOP Video    @tab     @tab  X
493 495
@item ZLIB                   @tab  X  @tab  X
494 496
    @tab part of LCL, encoder experimental
495 497
@item Zip Motion Blocks Video  @tab   X @tab  X
libavcodec/Makefile
386 386
OBJS-$(CONFIG_XL_DECODER)              += xl.o
387 387
OBJS-$(CONFIG_XSUB_DECODER)            += xsubdec.o
388 388
OBJS-$(CONFIG_XSUB_ENCODER)            += xsubenc.o
389
OBJS-$(CONFIG_YOP_DECODER)             += yop.o
389 390
OBJS-$(CONFIG_ZLIB_DECODER)            += lcldec.o
390 391
OBJS-$(CONFIG_ZLIB_ENCODER)            += lclenc.o
391 392
OBJS-$(CONFIG_ZMBV_DECODER)            += zmbv.o
libavcodec/allcodecs.c
207 207
    REGISTER_DECODER (WNV1, wnv1);
208 208
    REGISTER_DECODER (XAN_WC3, xan_wc3);
209 209
    REGISTER_DECODER (XL, xl);
210
    REGISTER_DECODER (YOP, yop);
210 211
    REGISTER_ENCDEC  (ZLIB, zlib);
211 212
    REGISTER_ENCDEC  (ZMBV, zmbv);
212 213

  
libavcodec/avcodec.h
30 30
#include "libavutil/avutil.h"
31 31

  
32 32
#define LIBAVCODEC_VERSION_MAJOR 52
33
#define LIBAVCODEC_VERSION_MINOR 61
33
#define LIBAVCODEC_VERSION_MINOR 62
34 34
#define LIBAVCODEC_VERSION_MICRO  0
35 35

  
36 36
#define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
......
209 209
    CODEC_ID_IFF_ILBM,
210 210
    CODEC_ID_IFF_BYTERUN1,
211 211
    CODEC_ID_KGV1,
212
    CODEC_ID_YOP,
212 213

  
213 214
    /* various PCM "codecs" */
214 215
    CODEC_ID_PCM_S16LE= 0x10000,
libavcodec/yop.c
1
/**
2
 * @file libavcodec/yop.c
3
 * Psygnosis YOP decoder
4
 *
5
 * Copyright (C) 2010 Mohamed Naufal Basheer <naufal11@gmail.com>
6
 * derived from the code by
7
 * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com>
8
 *
9
 * This file is part of FFmpeg.
10
 *
11
 * FFmpeg is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU Lesser General Public
13
 * License as published by the Free Software Foundation; either
14
 * version 2.1 of the License, or (at your option) any later version.
15
 *
16
 * FFmpeg is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
 * Lesser General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public
22
 * License along with FFmpeg; if not, write to the Free Software
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
 */
25

  
26
#include "libavutil/intreadwrite.h"
27

  
28
#include "avcodec.h"
29
#include "get_bits.h"
30

  
31
typedef struct YopDecContext {
32
    AVFrame frame;
33
    AVCodecContext *avctx;
34

  
35
    int num_pal_colors;
36
    int first_color[2];
37
    int frame_data_length;
38
    int row_pos;
39

  
40
    uint8_t *low_nibble;
41
    uint8_t *srcptr;
42
    uint8_t *dstptr;
43
    uint8_t *dstbuf;
44
} YopDecContext;
45

  
46
// These tables are taken directly from:
47
// http://wiki.multimedia.cx/index.php?title=Psygnosis_YOP
48

  
49
/**
50
 * Lookup table for painting macroblocks. Bytes 0-2 of each entry contain
51
 * the macroblock positions to be painted (taken as (0, B0, B1, B2)).
52
 * Byte 3 contains the number of bytes consumed on the input,
53
 * equal to max(bytes 0-2) + 1.
54
 */
55
static const uint8_t paint_lut[15][4] =
56
    {{1, 2, 3, 4}, {1, 2, 0, 3},
57
     {1, 2, 1, 3}, {1, 2, 2, 3},
58
     {1, 0, 2, 3}, {1, 0, 0, 2},
59
     {1, 0, 1, 2}, {1, 1, 2, 3},
60
     {0, 1, 2, 3}, {0, 1, 0, 2},
61
     {1, 1, 0, 2}, {0, 1, 1, 2},
62
     {0, 0, 1, 2}, {0, 0, 0, 1},
63
     {1, 1, 1, 2},
64
    };
65

  
66
/**
67
 * Lookup table for copying macroblocks. Each entry contains the respective
68
 * x and y pixel offset for the copy source.
69
 */
70
static const int8_t motion_vector[16][2] =
71
    {{-4, -4}, {-2, -4},
72
     { 0, -4}, { 2, -4},
73
     {-4, -2}, {-4,  0},
74
     {-3, -3}, {-1, -3},
75
     { 1, -3}, { 3, -3},
76
     {-3, -1}, {-2, -2},
77
     { 0, -2}, { 2, -2},
78
     { 4, -2}, {-2,  0},
79
    };
80

  
81
static av_cold int yop_decode_init(AVCodecContext *avctx)
82
{
83
    YopDecContext *s = avctx->priv_data;
84
    s->avctx = avctx;
85

  
86
    if (avctx->width & 1 || avctx->height & 1 ||
87
        avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
88
        av_log(avctx, AV_LOG_ERROR, "YOP has invalid dimensions\n");
89
        return -1;
90
    }
91

  
92
    avctx->pix_fmt = PIX_FMT_PAL8;
93

  
94
    s->num_pal_colors = avctx->extradata[0];
95
    s->first_color[0] = avctx->extradata[1];
96
    s->first_color[1] = avctx->extradata[2];
97

  
98
    if (s->num_pal_colors + s->first_color[0] > 256 ||
99
        s->num_pal_colors + s->first_color[1] > 256) {
100
        av_log(avctx, AV_LOG_ERROR,
101
               "YOP: palette parameters invalid, header probably corrupt\n");
102
        return AVERROR_INVALIDDATA;
103
    }
104

  
105
    return 0;
106
}
107

  
108
static av_cold int yop_decode_close(AVCodecContext *avctx)
109
{
110
    YopDecContext *s = avctx->priv_data;
111
    if (s->frame.data[0])
112
        avctx->release_buffer(avctx, &s->frame);
113
    return 0;
114
}
115

  
116
/**
117
 * Paints a macroblock using the pattern in paint_lut.
118
 * @param s codec context
119
 * @param tag the tag that was in the nibble
120
 */
121
static void yop_paint_block(YopDecContext *s, int tag)
122
{
123
    s->dstptr[0]                        = s->srcptr[0];
124
    s->dstptr[1]                        = s->srcptr[paint_lut[tag][0]];
125
    s->dstptr[s->frame.linesize[0]]     = s->srcptr[paint_lut[tag][1]];
126
    s->dstptr[s->frame.linesize[0] + 1] = s->srcptr[paint_lut[tag][2]];
127

  
128
    // The number of src bytes consumed is in the last part of the lut entry.
129
    s->srcptr += paint_lut[tag][3];
130
}
131

  
132
/**
133
 * Copies a previously painted macroblock to the current_block.
134
 * @param copy_tag the tag that was in the nibble
135
 */
136
static int yop_copy_previous_block(YopDecContext *s, int copy_tag)
137
{
138
    uint8_t *bufptr;
139

  
140
    // Calculate position for the copy source
141
    bufptr = s->dstptr + motion_vector[copy_tag][0] +
142
             s->frame.linesize[0] * motion_vector[copy_tag][1];
143
    if (bufptr < s->dstbuf) {
144
        av_log(s->avctx, AV_LOG_ERROR,
145
               "YOP: cannot decode, file probably corrupt\n");
146
        return AVERROR_INVALIDDATA;
147
    }
148

  
149
    s->dstptr[0]                        = bufptr[0];
150
    s->dstptr[1]                        = bufptr[1];
151
    s->dstptr[s->frame.linesize[0]]     = bufptr[s->frame.linesize[0]];
152
    s->dstptr[s->frame.linesize[0] + 1] = bufptr[s->frame.linesize[0] + 1];
153

  
154
    return 0;
155
}
156

  
157
/**
158
 * Returns the next nibble in sequence, consuming a new byte on the input
159
 * only if necessary.
160
 */
161
static uint8_t yop_get_next_nibble(YopDecContext *s)
162
{
163
    int ret;
164

  
165
    if (s->low_nibble) {
166
        ret           = *s->low_nibble & 0xf;
167
        s->low_nibble = NULL;
168
    }else {
169
        s->low_nibble = s->srcptr++;
170
        ret           = *s->low_nibble >> 4;
171
    }
172
    return ret;
173
}
174

  
175
/**
176
 * Takes s->dstptr to the next macroblock in sequence.
177
 */
178
static void yop_next_macroblock(YopDecContext *s)
179
{
180
    // If we are advancing to the next row of macroblocks
181
    if (s->row_pos == s->frame.linesize[0] - 2) {
182
        s->dstptr  += s->frame.linesize[0];
183
        s->row_pos =  0;
184
    }else {
185
        s->row_pos += 2;
186
    }
187
    s->dstptr += 2;
188
}
189

  
190
static int yop_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
191
                            AVPacket *avpkt)
192
{
193
    YopDecContext *s = avctx->priv_data;
194
    int tag, firstcolor, is_odd_frame;
195
    int ret, i;
196
    uint32_t *palette;
197

  
198
    if (s->frame.data[0])
199
        avctx->release_buffer(avctx, &s->frame);
200

  
201
    ret = avctx->get_buffer(avctx, &s->frame);
202
    if (ret < 0) {
203
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
204
        return ret;
205
    }
206

  
207
    s->frame.linesize[0] = avctx->width;
208

  
209
    s->dstbuf     = s->frame.data[0];
210
    s->dstptr     = s->frame.data[0];
211
    s->srcptr     = avpkt->data + 4;
212
    s->row_pos    = 0;
213
    s->low_nibble = NULL;
214

  
215
    is_odd_frame = avpkt->data[0];
216
    firstcolor   = s->first_color[is_odd_frame];
217
    palette      = (uint32_t *)s->frame.data[1];
218

  
219
    for (i = 0; i < s->num_pal_colors; i++, s->srcptr += 3)
220
        palette[i + firstcolor] = (s->srcptr[0] << 18) |
221
                                  (s->srcptr[1] << 10) |
222
                                  (s->srcptr[2] << 2);
223

  
224
    s->frame.palette_has_changed = 1;
225

  
226
    while (s->dstptr - s->dstbuf <
227
           avctx->width * avctx->height &&
228
           s->srcptr - avpkt->data < avpkt->size) {
229

  
230
        tag = yop_get_next_nibble(s);
231

  
232
        if (tag != 0xf) {
233
            yop_paint_block(s, tag);
234
        }else {
235
            tag = yop_get_next_nibble(s);
236
            ret = yop_copy_previous_block(s, tag);
237
            if (ret < 0) {
238
                avctx->release_buffer(avctx, &s->frame);
239
                return ret;
240
            }
241
        }
242
        yop_next_macroblock(s);
243
    }
244

  
245
    *data_size        = sizeof(AVFrame);
246
    *(AVFrame *) data = s->frame;
247
    return avpkt->size;
248
}
249

  
250
AVCodec yop_decoder = {
251
    "yop",
252
    CODEC_TYPE_VIDEO,
253
    CODEC_ID_YOP,
254
    sizeof(YopDecContext),
255
    yop_decode_init,
256
    NULL,
257
    yop_decode_close,
258
    yop_decode_frame,
259
    .long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP Video"),
260
};
libavformat/Makefile
260 260
OBJS-$(CONFIG_WSVQA_DEMUXER)             += westwood.o
261 261
OBJS-$(CONFIG_WV_DEMUXER)                += wv.o apetag.o id3v1.o
262 262
OBJS-$(CONFIG_XA_DEMUXER)                += xa.o
263
OBJS-$(CONFIG_YOP_DEMUXER)               += yop.o
263 264
OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER)        += yuv4mpeg.o
264 265
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER)      += yuv4mpeg.o
265 266

  
libavformat/allformats.c
207 207
    REGISTER_DEMUXER  (WSVQA, wsvqa);
208 208
    REGISTER_DEMUXER  (WV, wv);
209 209
    REGISTER_DEMUXER  (XA, xa);
210
    REGISTER_DEMUXER  (YOP, yop);
210 211
    REGISTER_MUXDEMUX (YUV4MPEGPIPE, yuv4mpegpipe);
211 212

  
212 213
    /* external libraries */
libavformat/avformat.h
22 22
#define AVFORMAT_AVFORMAT_H
23 23

  
24 24
#define LIBAVFORMAT_VERSION_MAJOR 52
25
#define LIBAVFORMAT_VERSION_MINOR 58
25
#define LIBAVFORMAT_VERSION_MINOR 59
26 26
#define LIBAVFORMAT_VERSION_MICRO  0
27 27

  
28 28
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
libavformat/yop.c
1
/**
2
 * @file libavformat/yop.c
3
 * Psygnosis YOP demuxer
4
 *
5
 * Copyright (C) 2010 Mohamed Naufal Basheer <naufal11@gmail.com>
6
 * derived from the code by
7
 * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com>
8
 *
9
 * This file is part of FFmpeg.
10
 *
11
 * FFmpeg is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU Lesser General Public
13
 * License as published by the Free Software Foundation; either
14
 * version 2.1 of the License, or (at your option) any later version.
15
 *
16
 * FFmpeg is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
 * Lesser General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public
22
 * License along with FFmpeg; if not, write to the Free Software
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
 */
25

  
26
#include "libavutil/intreadwrite.h"
27
#include "avformat.h"
28

  
29
typedef struct yop_dec_context {
30
    AVPacket video_packet;
31

  
32
    int odd_frame;
33
    int frame_size;
34
    int audio_block_length;
35
    int palette_size;
36
} YopDecContext;
37

  
38
static int yop_probe(AVProbeData *probe_packet)
39
{
40
    if (AV_RB16(probe_packet->buf) == AV_RB16("YO")  &&
41
        probe_packet->buf[6]                         &&
42
        probe_packet->buf[7]                         &&
43
        !(probe_packet->buf[8] & 1)                  &&
44
        !(probe_packet->buf[10] & 1))
45
        return AVPROBE_SCORE_MAX * 3 / 4;
46

  
47
    return 0;
48
}
49

  
50
static int yop_read_header(AVFormatContext *s, AVFormatParameters *ap)
51
{
52
    YopDecContext *yop = s->priv_data;
53
    ByteIOContext *pb  = s->pb;
54

  
55
    AVCodecContext *audio_dec, *video_dec;
56
    AVStream *audio_stream, *video_stream;
57

  
58
    int frame_rate, ret;
59

  
60
    audio_stream = av_new_stream(s, 0);
61
    video_stream = av_new_stream(s, 1);
62

  
63
    // Extra data that will be passed to the decoder
64
    video_stream->codec->extradata_size = 8;
65

  
66
    video_stream->codec->extradata = av_mallocz(video_stream->codec->extradata_size +
67
                                                FF_INPUT_BUFFER_PADDING_SIZE);
68

  
69
    if (!video_stream->codec->extradata)
70
        return AVERROR(ENOMEM);
71

  
72
    // Audio
73
    audio_dec               = audio_stream->codec;
74
    audio_dec->codec_type   = CODEC_TYPE_AUDIO;
75
    audio_dec->codec_id     = CODEC_ID_ADPCM_IMA_WS;
76
    audio_dec->channels     = 1;
77
    audio_dec->sample_rate  = 22050;
78

  
79
    // Video
80
    video_dec               = video_stream->codec;
81
    video_dec->codec_type   = CODEC_TYPE_VIDEO;
82
    video_dec->codec_id     = CODEC_ID_YOP;
83

  
84
    url_fskip(pb, 6);
85

  
86
    frame_rate              = get_byte(pb);
87
    yop->frame_size         = get_byte(pb) * 2048;
88
    video_dec->width        = get_le16(pb);
89
    video_dec->height       = get_le16(pb);
90

  
91
    video_stream->sample_aspect_ratio = (AVRational){1, 2};
92

  
93
    ret = get_buffer(pb, video_dec->extradata, 8);
94
    if (ret < 8)
95
        return ret < 0 ? ret : AVERROR_EOF;
96

  
97
    yop->palette_size       = video_dec->extradata[0] * 3 + 4;
98
    yop->audio_block_length = AV_RL16(video_dec->extradata + 6);
99

  
100
    // 1840 samples per frame, 1 nibble per sample; hence 1840/2 = 920
101
    if (yop->audio_block_length < 920 ||
102
        yop->audio_block_length + yop->palette_size >= yop->frame_size) {
103
        av_log(s, AV_LOG_ERROR, "YOP has invalid header\n");
104
        return AVERROR_INVALIDDATA;
105
    }
106

  
107
    url_fseek(pb, 2048, SEEK_SET);
108

  
109
    av_set_pts_info(video_stream, 32, 1, frame_rate);
110

  
111
    return 0;
112
}
113

  
114
static int yop_read_packet(AVFormatContext *s, AVPacket *pkt)
115
{
116
    YopDecContext *yop = s->priv_data;
117
    ByteIOContext *pb  = s->pb;
118

  
119
    int ret;
120
    int actual_video_data_size = yop->frame_size -
121
                                 yop->audio_block_length - yop->palette_size;
122

  
123
    yop->video_packet.stream_index = 1;
124

  
125
    if (yop->video_packet.data) {
126
        *pkt                   =  yop->video_packet;
127
        yop->video_packet.data =  NULL;
128
        yop->video_packet.size =  0;
129
        pkt->data[0]           =  yop->odd_frame;
130
        pkt->flags             |= PKT_FLAG_KEY;
131
        yop->odd_frame         ^= 1;
132
        return pkt->size;
133
    }
134
    ret = av_new_packet(&yop->video_packet,
135
                        yop->frame_size - yop->audio_block_length);
136
    if (ret < 0)
137
        return ret;
138

  
139
    yop->video_packet.pos = url_ftell(pb);
140

  
141
    ret = get_buffer(pb, yop->video_packet.data, yop->palette_size);
142
    if (ret < 0) {
143
        goto err_out;
144
    }else if (ret < yop->palette_size) {
145
        ret = AVERROR_EOF;
146
        goto err_out;
147
    }
148

  
149
    ret = av_get_packet(pb, pkt, 920);
150
    if (ret < 0)
151
        goto err_out;
152

  
153
    // Set position to the start of the frame
154
    pkt->pos = yop->video_packet.pos;
155

  
156
    url_fskip(pb, yop->audio_block_length - ret);
157

  
158
    ret = get_buffer(pb, yop->video_packet.data + yop->palette_size,
159
                     actual_video_data_size);
160
    if (ret < 0)
161
        goto err_out;
162
    else if (ret < actual_video_data_size)
163
        av_shrink_packet(&yop->video_packet, yop->palette_size + ret);
164

  
165
    // Arbitrarily return the audio data first
166
    return yop->audio_block_length;
167

  
168
err_out:
169
    av_free_packet(&yop->video_packet);
170
    return ret;
171
}
172

  
173
static int yop_read_close(AVFormatContext *s)
174
{
175
    YopDecContext *yop = s->priv_data;
176
    av_free_packet(&yop->video_packet);
177
    return 0;
178
}
179

  
180
static int yop_read_seek(AVFormatContext *s, int stream_index,
181
                         int64_t timestamp, int flags)
182
{
183
    YopDecContext *yop = s->priv_data;
184
    int64_t frame_pos, pos_min, pos_max;
185
    int frame_count;
186

  
187
    av_free_packet(&yop->video_packet);
188

  
189
    if (!stream_index)
190
        return -1;
191

  
192
    pos_min        = s->data_offset;
193
    pos_max        = url_fsize(s->pb) - yop->frame_size;
194
    frame_count    = (pos_max - pos_min) / yop->frame_size;
195

  
196
    timestamp      = FFMAX(0, FFMIN(frame_count, timestamp));
197

  
198
    frame_pos      = timestamp * yop->frame_size + pos_min;
199
    yop->odd_frame = timestamp & 1;
200

  
201
    url_fseek(s->pb, frame_pos, SEEK_SET);
202
    return 0;
203
}
204

  
205
AVInputFormat yop_demuxer = {
206
    "yop",
207
    NULL_IF_CONFIG_SMALL("Psygnosis YOP Format"),
208
    sizeof(YopDecContext),
209
    yop_probe,
210
    yop_read_header,
211
    yop_read_packet,
212
    yop_read_close,
213
    yop_read_seek,
214
    .extensions = "yop",
215
    .flags = AVFMT_GENERIC_INDEX,
216
};

Also available in: Unified diff