Revision 6cea494e

View differences:

libav/Makefile
4 4
OBJS= rm.o mpeg.o asf.o avienc.o jpeg.o swf.o wav.o raw.o \
5 5
	 avidec.o ffm.o \
6 6
	 avio.o aviobuf.o utils.o \
7
	 file.o img.o
7
	 file.o img.o au.o gif.o mov.o
8 8

  
9 9
ifeq ($(CONFIG_GRAB),yes)
10 10
OBJS+= grab.o audio.o 
libav/au.c
1
/* 
2
 * AU encoder and decoder
3
 * Copyright (c) 2001 Gerard Lantau.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
 */
19

  
20
/*
21
 * First version by Francois Revol revol@free.fr
22
 *
23
 * Reference documents:
24
 * http://www.opengroup.org/public/pubs/external/auformat.html
25
 * http://www.goice.co.jp/member/mo/formats/au.html
26
 */
27

  
28
#include "avformat.h"
29
#include "avi.h"
30

  
31
/* if we don't know the size in advance */
32
#define AU_UNKOWN_SIZE ((UINT32)(~0))
33

  
34
/* The ffmpeg codecs we support, and the IDs they have in the file */
35
CodecTag codec_au_tags[] = {
36
    { CODEC_ID_PCM_MULAW, 1 },
37
    { CODEC_ID_PCM_S16BE, 3 },
38
    { CODEC_ID_PCM_ALAW, 27 },
39
    { 0, 0 },
40
};
41

  
42
/* AUDIO_FILE header */
43
int put_au_header(ByteIOContext *pb, AVCodecContext *enc)
44
{
45
    int tag;
46

  
47
    tag = codec_get_tag(codec_au_tags, enc->codec_id);
48
    if (tag == 0)
49
        return -1;
50
    put_tag(pb, ".snd");       /* magic number */
51
    put_be32(pb, 24);           /* header size */
52
    put_be32(pb, AU_UNKOWN_SIZE); /* data size */
53
    put_be32(pb, (UINT32)tag);     /* codec ID */
54
    put_be32(pb, enc->sample_rate);
55
    put_be32(pb, (UINT32)enc->channels);
56
    return 0;
57
}
58

  
59
static int au_write_header(AVFormatContext *s)
60
{
61
    ByteIOContext *pb = &s->pb;
62

  
63
    s->priv_data = NULL;
64

  
65
    /* format header */
66
    if (put_au_header(pb, &s->streams[0]->codec) < 0) {
67
        return -1;
68
    }
69

  
70
    put_flush_packet(pb);
71

  
72
    return 0;
73
}
74

  
75
static int au_write_packet(AVFormatContext *s, int stream_index_ptr,
76
                           UINT8 *buf, int size)
77
{
78
    ByteIOContext *pb = &s->pb;
79
    put_buffer(pb, buf, size);
80
    return 0;
81
}
82

  
83
static int au_write_trailer(AVFormatContext *s)
84
{
85
    ByteIOContext *pb = &s->pb;
86
    offset_t file_size;
87

  
88
    if (!url_is_streamed(&s->pb)) {
89

  
90
        /* update file size */
91
        file_size = url_ftell(pb);
92
        url_fseek(pb, 8, SEEK_SET);
93
        put_be32(pb, (UINT32)(file_size - 24));
94
        url_fseek(pb, file_size, SEEK_SET);
95

  
96
        put_flush_packet(pb);
97
    }
98

  
99
    return 0;
100
}
101

  
102
/* au input */
103
static int au_read_header(AVFormatContext *s,
104
                           AVFormatParameters *ap)
105
{
106
    int size;
107
    unsigned int tag;
108
    ByteIOContext *pb = &s->pb;
109
    unsigned int id, codec, channels, rate;
110
    AVStream *st;
111

  
112
    /* check ".snd" header */
113
    tag = get_le32(pb);
114
    if (tag != MKTAG('.', 's', 'n', 'd'))
115
        return -1;
116
    size = get_be32(pb); /* header size */
117
    get_be32(pb); /* data size */
118
    
119
    id = get_be32(pb);
120
    rate = get_be32(pb);
121
    channels = get_be32(pb);
122
    
123
    codec = codec_get_id(codec_au_tags, id);
124

  
125
    if (size >= 24) {
126
        /* skip unused data */
127
        url_fseek(pb, size - 24, SEEK_CUR);
128
    }
129

  
130
    /* now we are ready: build format streams */
131
    st = malloc(sizeof(AVStream));
132
    if (!st)
133
        return -1;
134
    s->nb_streams = 1;
135
    s->streams[0] = st;
136

  
137
    st->id = 0;
138
    
139
    st->codec.codec_type = CODEC_TYPE_AUDIO;
140
    st->codec.codec_tag = id;
141
    st->codec.codec_id = codec;
142
    st->codec.channels = channels;
143
    st->codec.sample_rate = rate;
144
    return 0;
145
}
146

  
147
#define MAX_SIZE 4096
148

  
149
static int au_read_packet(AVFormatContext *s,
150
                           AVPacket *pkt)
151
{
152
    int packet_size, n, ret;
153

  
154
    if (url_feof(&s->pb))
155
        return -EIO;
156
    packet_size = url_get_packet_size(&s->pb);
157
    n = MAX_SIZE / packet_size;
158
    if (n <= 0)
159
        return n = 1;
160
    if (av_new_packet(pkt, n * packet_size))
161
        return -EIO;
162
    pkt->stream_index = 0;
163

  
164
    ret = get_buffer(&s->pb, pkt->data, pkt->size);
165
    if (ret < 0)
166
        av_free_packet(pkt);
167
    /* note: we need to modify the packet size here to handle the last
168
       packet */
169
    pkt->size = ret;
170
    return ret;
171
}
172

  
173
static int au_read_close(AVFormatContext *s)
174
{
175
    return 0;
176
}
177

  
178
AVFormat au_format = {
179
    "au",
180
    "SUN AU Format",
181
    "audio/basic",
182
    "au",
183
    CODEC_ID_PCM_S16BE,
184
    CODEC_ID_NONE,
185
    au_write_header,
186
    au_write_packet,
187
    au_write_trailer,
188

  
189
    au_read_header,
190
    au_read_packet,
191
    au_read_close,
192
};
libav/avformat.h
113 113
/* avienc.c */
114 114
extern AVFormat avi_format;
115 115

  
116
/* mov.c */
117
extern AVFormat mov_format;
118
extern AVFormat mp4_format;
119

  
116 120
/* jpegenc.c */
117 121
extern AVFormat mpjpeg_format;
118 122
extern AVFormat jpeg_format;
......
121 125
/* swfenc.c */
122 126
extern AVFormat swf_format;
123 127

  
128
/* gif.c */
129
extern AVFormat gif_format;
130
/* au.c */
131
extern AVFormat au_format;
132

  
124 133
/* wav.c */
125 134
extern AVFormat wav_format;
126 135

  
libav/gif.c
1
/*
2
 * Animated GIF encoder
3
 * Copyright (c) 2000 Gerard Lantau.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
 */
19

  
20
/*
21
 * First version by Francois Revol revol@free.fr
22
 *
23
 * Features and limitations:
24
 * - currently no compression is performed,
25
 *   in fact the size of the data is 9/8 the size of the image in 8bpp
26
 * - uses only a global standard palette
27
 * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
28
 *
29
 * Reference documents:
30
 * http://www.goice.co.jp/member/mo/formats/gif.html
31
 * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
32
 * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
33
 *
34
 * this url claims to have an LZW algorithm not covered by Unisys patent:
35
 * http://www.msg.net/utility/whirlgif/gifencod.html
36
 * could help reduce the size of the files _a lot_...
37
 * some sites mentions an RLE type compression also.
38
 */
39

  
40
#include "avformat.h"
41

  
42
/* bitstream minipacket size */
43
#define GIF_CHUNKS 100
44

  
45
/* slows down the decoding (and some browsers doesn't like it) */
46
/* #define GIF_ADD_APP_HEADER */
47

  
48
typedef struct {
49
    unsigned char r;
50
    unsigned char g;
51
    unsigned char b;
52
} rgb_triplet;
53

  
54
/* we use the standard 216 color palette */
55

  
56
/* this script was used to create the palette:
57
 * for r in 00 33 66 99 cc ff; do for g in 00 33 66 99 cc ff; do echo -n "    "; for b in 00 33 66 99 cc ff; do 
58
 *   echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done
59
 */
60

  
61
const rgb_triplet gif_clut[216] = {
62
    { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
63
    { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
64
    { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
65
    { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
66
    { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
67
    { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
68
    { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
69
    { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
70
    { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
71
    { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
72
    { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
73
    { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
74
    { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
75
    { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
76
    { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
77
    { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
78
    { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
79
    { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
80
    { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
81
    { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
82
    { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
83
    { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
84
    { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
85
    { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
86
    { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
87
    { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
88
    { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
89
    { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
90
    { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
91
    { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
92
    { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
93
    { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
94
    { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
95
    { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
96
    { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
97
    { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
98
};
99

  
100
/* The GIF format uses reversed order for bitstreams... */
101
/* at least they don't use PDP_ENDIAN :) */
102
/* so we 'extend' PutBitContext. hmmm, OOP :) */
103
/* seems this thing changed slightly since I wrote it... */
104

  
105
#ifdef ALT_BITSTREAM_WRITER
106
# error no ALT_BITSTREAM_WRITER support for now
107
#endif
108

  
109
void init_put_bits_rev(PutBitContext *s,
110
                   UINT8 *buffer, int buffer_size,
111
                   void *opaque,
112
                   void (*write_data)(void *, UINT8 *, int))
113
{
114
    init_put_bits(s, buffer, buffer_size, opaque, write_data);
115
}
116

  
117
void put_bits_rev(PutBitContext *s, int n, unsigned int value)
118
{
119
    unsigned int bit_buf;
120
    int bit_cnt;
121

  
122
#ifdef STATS
123
    st_out_bit_counts[st_current_index] += n;
124
#endif
125
    //    printf("put_bits=%d %x\n", n, value);
126
    assert(n == 32 || value < (1U << n));
127

  
128
    bit_buf = s->bit_buf;
129
    bit_cnt = 32 - s->bit_left; /* XXX:lazyness... was = s->bit_cnt; */
130

  
131
    //    printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf);
132
    /* XXX: optimize */
133
    if (n < (32-bit_cnt)) {
134
        bit_buf |= value << (bit_cnt);
135
        bit_cnt+=n;
136
    } else {
137
        bit_buf |= value << (bit_cnt);
138
        
139
        *s->buf_ptr = bit_buf & 0xff;
140
        s->buf_ptr[1] = (bit_buf >> 8) & 0xff;
141
        s->buf_ptr[2] = (bit_buf >> 16) & 0xff;
142
        s->buf_ptr[3] = (bit_buf >> 24) & 0xff;
143
        
144
        //printf("bitbuf = %08x\n", bit_buf);
145
        s->buf_ptr+=4;
146
        if (s->buf_ptr >= s->buf_end)
147
            puts("bit buffer overflow !!"); // should never happen ! who got rid of the callback ???
148
//            flush_buffer_rev(s);
149
        bit_cnt=bit_cnt + n - 32;
150
        if (bit_cnt == 0) {
151
            bit_buf = 0;
152
        } else {
153
            bit_buf = value >> (n - bit_cnt);
154
        }
155
    }
156

  
157
    s->bit_buf = bit_buf;
158
    s->bit_left = 32 - bit_cnt;
159
}
160

  
161
/* return the number of bits output */
162
INT64 get_bit_count_rev(PutBitContext *s)
163
{
164
    return get_bit_count(s);
165
}
166

  
167
void align_put_bits_rev(PutBitContext *s)
168
{
169
    align_put_bits(s);
170
}
171

  
172
/* pad the end of the output stream with zeros */
173
void flush_put_bits_rev(PutBitContext *s)
174
{
175
    while (s->bit_left < 32) {
176
        /* XXX: should test end of buffer */
177
        *s->buf_ptr++=s->bit_buf & 0xff;
178
        s->bit_buf>>=8;
179
        s->bit_left+=8;
180
    }
181
//    flush_buffer_rev(s);
182
    s->bit_left=32;
183
    s->bit_buf=0;
184
}
185

  
186
/* !RevPutBitContext */
187

  
188
typedef struct {
189
    UINT8 buffer[100]; /* data chunks */
190
    INT64 time, file_time;
191
} GIFContext;
192

  
193
static int gif_write_header(AVFormatContext *s)
194
{
195
    GIFContext *gif;
196
    ByteIOContext *pb = &s->pb;
197
    AVCodecContext *enc, *video_enc;
198
    int i, width, height, rate;
199

  
200
/* XXX: do we reject audio streams or just ignore them ?
201
    if(s->nb_streams > 1)
202
        return -1;
203
*/
204

  
205
    gif = malloc(sizeof(GIFContext));
206
    if (!gif)
207
        return -1;
208
    s->priv_data = gif;
209

  
210
    gif->time = 0;
211
    gif->file_time = 0;
212

  
213
    video_enc = NULL;
214
    for(i=0;i<s->nb_streams;i++) {
215
        enc = &s->streams[i]->codec;
216
        if (enc->codec_type != CODEC_TYPE_AUDIO)
217
            video_enc = enc;
218
    }
219

  
220
    if (!video_enc) {
221
        free(gif);
222
        return -1;
223
    } else {
224
        width = video_enc->width;
225
        height = video_enc->height;
226
        rate = video_enc->frame_rate;
227
    }
228

  
229
    /* XXX: is it allowed ? seems to work so far... */
230
    video_enc->pix_fmt = PIX_FMT_RGB24;
231

  
232
    /* GIF header */
233

  
234
    put_tag(pb, "GIF");
235
    put_tag(pb, "89a");
236
    put_le16(pb, width);
237
    put_le16(pb, height);
238

  
239
    put_byte(pb, 0xf7); /* flags: global clut, 256 entries */
240
    put_byte(pb, 0x1f); /* background color index */
241
    put_byte(pb, 0); /* aspect ratio */
242

  
243
    /* the global palette */
244

  
245
    put_buffer(pb, (unsigned char *)gif_clut, 216*3);
246
    for(i=0;i<((256-216)*3);i++)
247
       put_byte(pb, 0);
248

  
249
    /* application extension header */
250
    /* XXX: not really sure what to put in here... */
251
#ifdef GIF_ADD_APP_HEADER
252
    put_byte(pb, 0x21);
253
    put_byte(pb, 0xff);
254
    put_byte(pb, 0x0b);
255
    put_tag(pb, "NETSCAPE2.0");
256
    put_byte(pb, 0x03);
257
    put_byte(pb, 0x01);
258
    put_byte(pb, 0x00);
259
    put_byte(pb, 0x00);
260
#endif
261

  
262
    put_flush_packet(&s->pb);
263
    return 0;
264
}
265

  
266
/* this is maybe slow, but allows for extensions */
267
static inline unsigned char gif_clut_index(rgb_triplet *clut, UINT8 r, UINT8 g, UINT8 b)
268
{
269
    return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
270
}
271

  
272
/* chunk writer callback */
273
/* !!! XXX:deprecated
274
static void gif_put_chunk(void *pbctx, UINT8 *buffer, int count)
275
{
276
    ByteIOContext *pb = (ByteIOContext *)pbctx;
277
    put_byte(pb, (UINT8)count);
278
    put_buffer(pb, buffer, count);
279
}
280
*/
281

  
282
static int gif_write_video(AVFormatContext *s, 
283
                           AVCodecContext *enc, UINT8 *buf, int size)
284
{
285
    ByteIOContext *pb = &s->pb;
286
    GIFContext *gif = s->priv_data;
287
    int i, left, jiffies;
288
    INT64 delay;
289
    PutBitContext p;
290
    UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */
291

  
292

  
293
    /* graphic control extension block */
294
    put_byte(pb, 0x21);
295
    put_byte(pb, 0xf9);
296
    put_byte(pb, 0x04); /* block size */
297
    put_byte(pb, 0x04); /* flags */
298
    
299
    /* 1 jiffy is 1/70 s */
300
    /* the delay_time field indicates the number of jiffies - 1 */
301
    delay = gif->file_time - gif->time;
302

  
303
    /* XXX: should use delay, in order to be more accurate */
304
    /* instead of using the same rounded value each time */
305
    /* XXX: don't even remember if I really use it for now */
306
    jiffies = (70*FRAME_RATE_BASE/enc->frame_rate) - 1;
307

  
308
    put_le16(pb, jiffies);
309

  
310
    put_byte(pb, 0x1f); /* transparent color index */
311
    put_byte(pb, 0x00);
312

  
313
    /* image block */
314

  
315
    put_byte(pb, 0x2c);
316
    put_le16(pb, 0);
317
    put_le16(pb, 0);
318
    put_le16(pb, enc->width);
319
    put_le16(pb, enc->height);
320
    put_byte(pb, 0x00); /* flags */
321
    /* no local clut */
322

  
323
    put_byte(pb, 0x08);
324

  
325
    left=size/3;
326

  
327
    /* XXX:deprecated */
328
    /*init_put_bits_rev(&p, buffer, sizeof(buf), (void *)pb, gif_put_chunk); *//* mmm found a but in my code: s/sizeof(buf)/150/ */
329

  
330
    init_put_bits_rev(&p, buffer, 130, NULL, NULL);
331

  
332
/*
333
 * the thing here is the bitstream is written as little packets, with a size byte before
334
 * but it's still the same bitstream between packets (no flush !)
335
 */
336

  
337
    while(left>0) {
338

  
339
        put_bits_rev(&p, 9, 0x0100); /* clear code */
340

  
341
        for(i=0;i<GIF_CHUNKS;i++) {
342
            put_bits_rev(&p, 9, gif_clut_index(NULL, *buf, buf[1], buf[2]));
343
            buf+=3;
344
        }
345

  
346
        if(left<=GIF_CHUNKS) {
347
            put_bits_rev(&p, 9, 0x101); /* end of stream */
348
            flush_put_bits_rev(&p);
349
        }
350
        if(pbBufPtr(&p) - p.buf > 0) {
351
            put_byte(pb, pbBufPtr(&p) - p.buf); /* byte count of the packet */
352
            put_buffer(pb, p.buf, pbBufPtr(&p) - p.buf); /* the actual buffer */
353
            p.data_out_size += pbBufPtr(&p) - p.buf;
354
            p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
355
        }
356
        if(left<=GIF_CHUNKS) {
357
            put_byte(pb, 0x00); /* end of image block */
358
        }
359

  
360
        left-=GIF_CHUNKS;
361
    }
362

  
363
    put_flush_packet(&s->pb);
364
    return 0;
365
}
366

  
367
static int gif_write_packet(AVFormatContext *s, int stream_index, 
368
                           UINT8 *buf, int size)
369
{
370
    AVCodecContext *codec = &s->streams[stream_index]->codec;
371
    if (codec->codec_type == CODEC_TYPE_AUDIO)
372
        return 0; /* just ignore audio */
373
    else
374
        return gif_write_video(s, codec, buf, size);
375
}
376

  
377
static int gif_write_trailer(AVFormatContext *s)
378
{
379
    GIFContext *gif = s->priv_data;
380
    ByteIOContext *pb = &s->pb;
381

  
382
    put_byte(pb, 0x3b);
383
    put_flush_packet(&s->pb);
384

  
385
    free(gif);
386
    return 0;
387
}
388

  
389
AVFormat gif_format = {
390
    "gif",
391
    "GIF Animation",
392
    "image/gif",
393
    "gif",
394
    CODEC_ID_NONE,
395
    CODEC_ID_RAWVIDEO,
396
    gif_write_header,
397
    gif_write_packet,
398
    gif_write_trailer,
399

  
400
    NULL, /* read_header */
401
    NULL, /* read_packet */
402
    NULL, /* read_close */
403
};
404

  
libav/mov.c
1
/*
2
 * MOV decoder.
3
 * Copyright (c) 2001 Gerard Lantau.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
 */
19
#include "avformat.h"
20
#include "avi.h"
21

  
22
/*
23
 * First version by Francois Revol revol@free.fr
24
 * 
25
 * Features and limitations:
26
 * - reads most of the QT files I have (at least the structure), 
27
 *   the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement.
28
 * - ffmpeg has nearly none of the usual QuickTime codecs,
29
 *   although I succesfully dumped raw and mp3 audio tracks off .mov files.
30
 *   Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html
31
 * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes
32
 *   (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at
33
 *   http://mpeg.telecomitalialab.com/faq.htm
34
 * - the code is quite ugly... maybe I won't do it recursive next time :-)
35
 * 
36
 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/
37
 * when coding this :) (it's a writer anyway)
38
 * 
39
 * Reference documents:
40
 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
41
 * Apple:
42
 *  http://developer.apple.com/techpubs/quicktime/qtdevdocs/QTFF/qtff.html
43
 *  http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf
44
 * QuickTime is a trademark of Apple (AFAIK :))
45
 */
46

  
47
#define DEBUG
48

  
49
#ifdef DEBUG
50
/*
51
 * XXX: static sux, even more in a multithreaded environment...
52
 * Avoid them. This is here just to help debugging.
53
 */
54
static int debug_indent = 0;
55
void print_atom(const char *str, UINT32 type, UINT64 offset, UINT64 size)
56
{
57
    unsigned int tag, i;
58
    tag = (unsigned int) type;
59
    i=debug_indent;
60
    if(tag == 0) tag = MKTAG('N', 'U', 'L', 'L');
61
    while(i--)
62
        printf("|");
63
    printf("parse:");
64
    printf(" %s: tag=%c%c%c%c offset=%d size=0x%x\n",
65
           str, tag & 0xff,
66
           (tag >> 8) & 0xff,
67
           (tag >> 16) & 0xff,
68
           (tag >> 24) & 0xff,
69
           (unsigned int)offset,
70
           (unsigned int)size);
71
}
72
#endif
73

  
74
/* some streams in QT (and in MP4 mostly) aren't either video nor audio */
75
/* so we first list them as this, then clean up the list of streams we give back, */
76
/* getting rid of these */
77
#define CODEC_TYPE_MOV_OTHER 2
78

  
79
CodecTag mov_video_tags[] = {
80
/*  { CODEC_ID_, MKTAG('c', 'v', 'i', 'd') }, *//* Cinepak */
81
/*  { CODEC_ID_JPEG, MKTAG('j', 'p', 'e', 'g') }, *//* JPEG */
82
    { CODEC_ID_H263, MKTAG('r', 'a', 'w', ' ') }, /* Uncompressed RGB */
83
    { CODEC_ID_H263, MKTAG('Y', 'u', 'v', '2') }, /* Uncompressed YUV422 */
84
/* Graphics */
85
/* Animation */
86
/* Apple video */
87
/* Kodak Photo CD */
88
/*    { CODEC_ID_JPEG, MKTAG('j', 'p', 'e', 'g') }, *//* JPEG ? */
89
    { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */
90
    { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format A) */
91
    { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format B) */
92
/*    { CODEC_ID_GIF, MKTAG('g', 'i', 'f', ' ') }, *//* embedded gif files as frames (usually one "click to play movie" frame) */
93
/* Sorenson video */
94
    { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, /* OpenDiVX *//* yeah ! */
95
    { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') }, /* OpenDiVX *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */
96
/*    { CODEC_ID_, MKTAG('I', 'V', '5', '0') }, *//* Indeo 5.0 */
97
    { 0, 0 }, 
98
};
99

  
100
CodecTag mov_audio_tags[] = {
101
/*    { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, *//* uncompressed */
102
    { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */
103
    { CODEC_ID_PCM_S8, MKTAG('t', 'w', 'o', 's') }, /* 8 bits */
104
    { CODEC_ID_PCM_U8, 0x20776172 }, /* 8 bits unsigned */
105
    { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /*  */
106
    { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /*  */
107
    { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /*  */
108
/*    { CODEC_ID_, MKTAG('i', 'm', 'a', '4') }, *//* IMA-4 */
109

  
110
    { CODEC_ID_MP2, MKTAG('.', 'm', 'p', '3') }, /* MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag */
111
    { CODEC_ID_MP2, 0x6D730055 }, /* MPEG layer 3 */
112
    { CODEC_ID_MP2, 0x5500736D }, /* MPEG layer 3 *//* XXX: check endianness */
113
/*    { CODEC_ID_OGG_VORBIS, MKTAG('O', 'g', 'g', 'S') }, *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */
114
/* MP4 tags */
115
/*    { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, *//* MPEG 4 AAC or audio ? */
116
                                                     /* The standard for mpeg4 audio is still not normalised AFAIK anyway */
117
    { 0, 0 }, 
118
};
119

  
120
/* the QuickTime file format is quite convoluted...
121
 * it has lots of index tables, each indexing something in another one...
122
 * Here we just use what is needed to read the chunks
123
 */
124

  
125
typedef struct MOV_sample_to_chunk_tbl {
126
    long first;
127
    long count;
128
    long id;
129
} MOV_sample_to_chunk_tbl;
130

  
131
typedef struct MOVStreamContext {
132
    int ffindex; /* the ffmpeg stream id */
133
    int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */
134
    long next_chunk;
135
    long chunk_count;
136
    INT64 *chunk_offsets;
137
    long sample_to_chunk_sz;
138
    MOV_sample_to_chunk_tbl *sample_to_chunk;
139
    long sample_size;
140
    long sample_count;
141
    long *sample_sizes;
142
} MOVStreamContext;
143

  
144
typedef struct MOVContext {
145
    int mp4; /* set to 1 as soon as we are sure that the file is an .mp4 file (even some header parsing depends on this) */
146
    AVFormatContext *fc;
147
    long time_scale;
148
    int found_moov; /* when both 'moov' and 'mdat' sections has been found */
149
    int found_mdat; /* we suppose we have enough data to read the file */
150
    INT64 mdat_size;
151
    INT64 mdat_offset;
152
    int total_streams;
153
    /* some streams listed here aren't presented to the ffmpeg API, since they aren't either video nor audio
154
     * but we need the info to be able to skip data from those streams in the 'mdat' section
155
     */
156
    MOVStreamContext *streams[MAX_STREAMS];
157
    
158
    INT64 next_chunk_offset;
159
} MOVContext;
160

  
161

  
162
struct MOVParseTableEntry;
163

  
164
/* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */
165

  
166
/* those functions parse an atom */
167
/* return code:
168
 1: found what I wanted, exit
169
 0: continue to parse next atom
170
 -1: error occured, exit
171
 */
172
typedef int (*mov_parse_function)(struct MOVParseTableEntry *parse_table,
173
                                  ByteIOContext *pb,
174
                                  UINT32 atom_type,
175
                                  INT64 atom_offset, /* after the size and type field (and eventually the extended size) */
176
                                  INT64 atom_size, /* total size (excluding the size and type fields) */
177
                                  void *param);
178

  
179
/* links atom IDs to parse functions */
180
typedef struct MOVParseTableEntry {
181
    UINT32 type;
182
    mov_parse_function func;
183
} MOVParseTableEntry;
184

  
185
static int parse_leaf(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
186
{
187
#ifdef DEBUG
188
    print_atom("leaf", atom_type, atom_offset, atom_size);
189
#endif
190
    if(atom_size>1)
191
        url_fskip(pb, atom_size);
192
/*        url_seek(pb, atom_offset+atom_size, SEEK_SET); */
193
    return 0;
194
}
195

  
196

  
197
static int parse_default(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
198
{
199
    UINT32 type, foo=0;
200
    UINT64 offset, size;
201
    UINT64 total_size = 0;
202
    int i;
203
    int err = 0;
204
    foo=0;
205
#ifdef DEBUG
206
    print_atom("default", atom_type, atom_offset, atom_size);
207
    debug_indent++;
208
#endif
209
    
210
    offset = atom_offset;
211

  
212
    if(atom_size < 0)
213
        atom_size = 0x0FFFFFFFFFFFFFFF;
214
    while((total_size < atom_size) && !url_feof(pb) && !err) {
215
        size=atom_size;
216
        type=0L;
217
        if(atom_size >= 8) {
218
            size = get_be32(pb);
219
            type = get_le32(pb);
220
        }
221
        total_size += 8;
222
        offset+=8;
223
//        printf("type: %08lx  sz: %08lx", type, size);
224
        if(size == 1) { /* 64 bit extended size */
225
            size = get_be64(pb);
226
            offset+=8;
227
            total_size+=8;
228
            size-=8;
229
        }
230
        if(size == 0)
231
            size = atom_size - total_size;
232
        size-=8;
233
        for(i=0; parse_table[i].type != 0L && parse_table[i].type != type; i++);
234
        
235
//        printf(" i=%ld\n", i);
236
        if(parse_table[i].type == NULL) { /* skip leaf atoms data */
237
//            url_seek(pb, atom_offset+atom_size, SEEK_SET);
238
#ifdef DEBUG
239
            print_atom("unknown", type, offset, size);
240
#endif
241
            url_fskip(pb, size);
242
        } else
243
            err = (parse_table[i].func)(parse_table, pb, type, offset, size, param);
244

  
245
        offset+=size;
246
        total_size+=size;
247
    }
248

  
249
#ifdef DEBUG
250
    debug_indent--;
251
#endif
252
    return err;
253
}
254

  
255
static int parse_mvhd(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
256
{
257
    MOVContext *c;
258
#ifdef DEBUG
259
    print_atom("mvhd", atom_type, atom_offset, atom_size);
260
#endif
261
    c = (MOVContext *)param;
262

  
263
    get_byte(pb); /* version */
264
    get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
265

  
266
    get_be32(pb); /* creation time */
267
    get_be32(pb); /* modification time */
268
    c->time_scale = get_be32(pb); /* time scale */
269
    get_be32(pb); /* duration */
270
    get_be32(pb); /* preferred scale */
271
    
272
    get_be16(pb); /* preferred volume */
273

  
274
    url_fskip(pb, 10); /* reserved */
275

  
276
    url_fskip(pb, 36); /* display matrix */
277

  
278
    get_be32(pb); /* preview time */
279
    get_be32(pb); /* preview duration */
280
    get_be32(pb); /* poster time */
281
    get_be32(pb); /* selection time */
282
    get_be32(pb); /* selection duration */
283
    get_be32(pb); /* current time */
284
    get_be32(pb); /* next track ID */
285
    
286
    return 0;
287
}
288

  
289
/* this atom should contain all header atoms */
290
static int parse_moov(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
291
{
292
    int err;
293
    MOVContext *c;
294
#ifdef DEBUG
295
    print_atom("moov", atom_type, atom_offset, atom_size);
296
#endif
297
    c = (MOVContext *)param;
298

  
299
    err = parse_default(parse_table, pb, atom_type, atom_offset, atom_size, param);
300
    /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
301
    /* so we don't parse the whole file if over a network */
302
    c->found_moov=1;
303
    if(c->found_mdat)
304
        return 1; /* found both, just go */
305
    return 0; /* now go for mdat */
306
}
307

  
308
/* this atom contains actual media data */
309
static int parse_mdat(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
310
{
311
    int err;
312
    MOVContext *c;
313
#ifdef DEBUG
314
    print_atom("mdat", atom_type, atom_offset, atom_size);
315
#endif
316
    c = (MOVContext *)param;
317

  
318
    if(atom_size == 0) /* wrong one (MP4) */
319
        return 0;
320
    c->found_mdat=1;
321
    c->mdat_offset = atom_offset;
322
    c->mdat_size = atom_size;
323
    if(c->found_moov)
324
        return 1; /* found both, just go */
325
    url_fskip(pb, atom_size);
326
    return 0; /* now go for moov */
327
}
328

  
329
static int parse_trak(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
330
{
331
    MOVContext *c;
332
    AVStream *st;
333
    MOVStreamContext *sc;
334
#ifdef DEBUG
335
    print_atom("trak", atom_type, atom_offset, atom_size);
336
#endif
337

  
338
    c = (MOVContext *)param;
339
    st = malloc(sizeof(AVStream));
340
        if (!st) return -2;
341
    memset(st, 0, sizeof(AVStream));
342
    c->fc->streams[c->fc->nb_streams] = st;
343
    sc = malloc(sizeof(MOVStreamContext));
344
    st->priv_data = sc;
345
    st->codec.codec_type = CODEC_TYPE_MOV_OTHER;
346
    c->streams[c->fc->nb_streams++] = sc;
347
    return parse_default(parse_table, pb, atom_type, atom_offset, atom_size, param);
348
}
349

  
350
static int parse_tkhd(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
351
{
352
    MOVContext *c;
353
    AVStream *st;
354
#ifdef DEBUG
355
    print_atom("tkhd", atom_type, atom_offset, atom_size);
356
#endif
357

  
358
    c = (MOVContext *)param;
359
    st = c->fc->streams[c->fc->nb_streams-1];
360
    
361
    get_byte(pb); /* version */
362

  
363
    get_byte(pb); get_byte(pb);
364
    get_byte(pb); /* flags */
365
    /*
366
    MOV_TRACK_ENABLED 0x0001
367
    MOV_TRACK_IN_MOVIE 0x0002
368
    MOV_TRACK_IN_PREVIEW 0x0004
369
    MOV_TRACK_IN_POSTER 0x0008
370
    */
371

  
372
    get_be32(pb); /* creation time */
373
    get_be32(pb); /* modification time */
374
    st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/
375
    get_be32(pb); /* reserved */
376
    get_be32(pb); /* duration */
377
    get_be32(pb); /* reserved */
378
    get_be32(pb); /* reserved */
379
    
380
    get_be16(pb); /* layer */
381
    get_be16(pb); /* alternate group */
382
    get_be16(pb); /* volume */
383
    get_be16(pb); /* reserved */
384

  
385
    url_fskip(pb, 36); /* display matrix */
386

  
387
    /* those are fixed-point */
388
    st->codec.width = get_be32(pb) >> 16; /* track width */
389
    st->codec.height = get_be32(pb) >> 16; /* track height */
390
    
391
    return 0;
392
}
393

  
394
static int parse_hdlr(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
395
{
396
    MOVContext *c;
397
    int len;
398
    char *buf, ch;
399
    UINT32 type;
400
    AVStream *st;
401
    UINT32 ctype;
402
#ifdef DEBUG
403
    print_atom("hdlr", atom_type, atom_offset, atom_size);
404
#endif
405
    c = (MOVContext *)param;
406
    st = c->fc->streams[c->fc->nb_streams-1];
407

  
408
    get_byte(pb); /* version */
409
    get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
410

  
411
    /* component type */
412
    ctype = get_le32(pb);
413
    type = get_le32(pb); /* component subtype */
414

  
415
#ifdef DEBUG
416
    printf("ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], ctype);
417
    printf("stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]);
418
#endif
419
#ifdef DEBUG
420
/* XXX: yeah this is ugly... */
421
    if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */
422
        if(type == MKTAG('v', 'i', 'd', 'e'))
423
            puts("hdlr: vide");
424
        else if(type == MKTAG('s', 'o', 'u', 'n'))
425
            puts("hdlr: soun");
426
    } else if(ctype == 0) { /* MP4 */
427
        if(type == MKTAG('v', 'i', 'd', 'e'))
428
            puts("hdlr: vide");
429
        else if(type == MKTAG('s', 'o', 'u', 'n'))
430
            puts("hdlr: soun");
431
        else if(type == MKTAG('o', 'd', 's', 'm'))
432
            puts("hdlr: odsm");
433
        else if(type == MKTAG('s', 'd', 's', 'm'))
434
            puts("hdlr: sdsm");
435
    } else puts("hdlr: meta");
436
#endif
437

  
438
    if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */
439
        if(type == MKTAG('v', 'i', 'd', 'e'))
440
            st->codec.codec_type = CODEC_TYPE_VIDEO;
441
        else if(type == MKTAG('s', 'o', 'u', 'n'))
442
            st->codec.codec_type = CODEC_TYPE_AUDIO;
443
    } else if(ctype == 0) { /* MP4 */
444
        if(type == MKTAG('v', 'i', 'd', 'e'))
445
            st->codec.codec_type = CODEC_TYPE_VIDEO;
446
        else if(type == MKTAG('s', 'o', 'u', 'n'))
447
            st->codec.codec_type = CODEC_TYPE_AUDIO;
448
    }
449
    get_be32(pb); /* component  manufacture */
450
    get_be32(pb); /* component flags */
451
    get_be32(pb); /* component flags mask */
452

  
453
    if(atom_size <= 24)
454
        return 0; /* nothing left to read */
455
    /* XXX: MP4 uses a C string, not a pascal one */
456
    /* component name */
457
    if(c->mp4) {
458
#ifdef DEBUG
459
        puts("MP4!!!");
460
#endif
461
        while(ch=get_byte(pb));
462
    } else {
463
        len = get_byte(pb);
464
        if(len) {
465
            buf = malloc(len+1);
466
            get_buffer(pb, buf, len);
467
            buf[len] = '\0';
468
#ifdef DEBUG
469
            puts(buf);
470
#endif
471
            free(buf);
472
        }
473
    }
474
    
475
    return 0;
476
}
477

  
478
static int parse_stsd(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
479
{
480
    MOVContext *c;
481
    int entries, size, samp_sz, frames_per_sample;
482
    char *buf;
483
    UINT32 format;
484
    AVStream *st;
485
#ifdef DEBUG
486
    print_atom("stsd", atom_type, atom_offset, atom_size);
487
#endif
488
    c = (MOVContext *)param;
489
    st = c->fc->streams[c->fc->nb_streams-1];
490

  
491
    get_byte(pb); /* version */
492
    get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
493

  
494

  
495
    entries = get_be32(pb);
496

  
497
    while(entries--) {
498
        size = get_be32(pb); /* size */
499
        format = get_le32(pb); /* data format */
500
        
501
        get_be32(pb); /* reserved */
502
        get_be16(pb); /* reserved */
503
        get_be16(pb); /* index */
504
/*        if(format == MKTAG('m', 'p', '4', 'v')) */
505
/*            st->codec.codec_type=CODEC_TYPE_VIDEO; *//* force things (XXX: was this for .mp4 ?) */
506
        if(st->codec.codec_type==CODEC_TYPE_VIDEO) {
507
            st->codec.codec_tag = format;
508
            st->codec.codec_id = codec_get_id(mov_video_tags, format);
509
            get_be16(pb); /* version */
510
            get_be16(pb); /* revision level */
511
            get_be32(pb); /* vendor */
512
            get_be32(pb); /* temporal quality */
513
            get_be32(pb); /* spacial quality */
514
            st->codec.width = get_be16(pb); /* width */
515
            st->codec.height = get_be16(pb); /* height */
516
            get_be32(pb); /* horiz resolution */
517
            get_be32(pb); /* vert resolution */
518
            get_be32(pb); /* data size, always 0 */
519
            frames_per_sample = get_be16(pb); /* frame per samples */
520
#ifdef DEBUG
521
            printf("frames/samples = %ld\n", frames_per_sample);
522
#endif
523
            url_fskip(pb, 32); /* codec name */
524

  
525
            get_be16(pb); /* depth */
526
            get_be16(pb); /* colortable id */
527
            get_be16(pb); /*  */
528
            get_be16(pb); /*  */
529
            
530
            st->codec.sample_rate = 25 * FRAME_RATE_BASE;
531
            
532
            if(size > 16)
533
                url_fskip(pb, size-(16+24+18+32));
534
        } else {
535
            st->codec.codec_tag = format;
536

  
537
            get_be16(pb); /* version */
538
            get_be16(pb); /* revision level */
539
            get_be32(pb); /* vendor */
540

  
541
            st->codec.channels = get_be16(pb);/* channel count */
542
            samp_sz = get_be16(pb); /* sample size */
543
#ifdef DEBUG
544
            if(samp_sz != 16)
545
                puts("!!! stsd: audio sample size is not 16 bit !");
546
#endif            
547
            st->codec.codec_id = codec_get_id(mov_audio_tags, format);
548
            /* handle specific s8 codec */
549
            if (st->codec.codec_id == CODEC_ID_PCM_S16BE && samp_sz == 8)
550
            st->codec.codec_id = CODEC_ID_PCM_S8;
551

  
552
            get_be16(pb); /* compression id = 0*/
553
            get_be16(pb); /* packet size = 0 */
554
            
555
            st->codec.sample_rate = ((get_be32(pb) >> 16));
556
            st->codec.bit_rate = 0;
557

  
558
            /* this is for .mp4 files */
559
            if(format == MKTAG('m', 'p', '4', 'v')) { /* XXX */
560
                st->codec.codec_type=CODEC_TYPE_VIDEO; /* force things */
561
                st->codec.codec_id = CODEC_ID_MPEG4;
562
                st->codec.frame_rate = 25;
563
                st->codec.bit_rate = 100000;
564
            }
565

  
566
#if 0
567

  
568
            get_be16(pb); get_be16(pb); /*  */
569
            get_be16(pb); /*  */
570
            get_be16(pb); /*  */
571
            get_be16(pb); /*  */
572
            get_be16(pb); /*  */
573
#endif            
574
            if(size > 16)
575
                url_fskip(pb, size-(16+20));
576
        }
577
#ifdef DEBUG
578
        printf("4CC= %c%c%c%c\n", *((char *)&format), ((char *)&format)[1], ((char *)&format)[2], ((char *)&format)[3]);
579
#endif
580
    }
581
/*
582
    if(len) {
583
        buf = malloc(len+1);
584
        get_buffer(pb, buf, len);
585
        buf[len] = '\0';
586
        puts(buf);
587
        free(buf);
588
    }
589
*/
590
    return 0;
591
}
592

  
593
static int parse_stco(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
594
{
595
    MOVContext *c;
596
    int entries, i;
597
    AVStream *st;
598
    MOVStreamContext *sc;
599
#ifdef DEBUG
600
    print_atom("stco", atom_type, atom_offset, atom_size);
601
#endif
602
    c = (MOVContext *)param;
603
    st = c->fc->streams[c->fc->nb_streams-1];
604
    sc = (MOVStreamContext *)st->priv_data;
605
    
606
    get_byte(pb); /* version */
607
    get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
608

  
609
    entries = get_be32(pb);
610
    sc->chunk_count = entries;
611
    sc->chunk_offsets = malloc(entries * sizeof(INT64));
612
    if(atom_type == MKTAG('s', 't', 'c', 'o')) {
613
        for(i=0; i<entries; i++) {
614
            sc->chunk_offsets[i] = get_be32(pb);
615
            /*printf("chunk offset=%ld\n", sc->chunk_offsets[i]);*/
616
        }
617
    } else if(atom_type == MKTAG('c', 'o', '6', '4')) {
618
        for(i=0; i<entries; i++) {
619
            sc->chunk_offsets[i] = get_be64(pb);
620
            /*printf("chunk offset=%ld\n", sc->chunk_offsets[i]);*/
621
        }
622
    } else
623
        return -1;
624
    return 0;
625
}
626

  
627
static int parse_stsc(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
628
{
629
    MOVContext *c;
630
    int entries, i;
631
    AVStream *st;
632
    MOVStreamContext *sc;
633
#ifdef DEBUG
634
    print_atom("stsc", atom_type, atom_offset, atom_size);
635
#endif
636
    c = (MOVContext *)param;
637
    st = c->fc->streams[c->fc->nb_streams-1];
638
    sc = (MOVStreamContext *)st->priv_data;
639
    
640
    get_byte(pb); /* version */
641
    get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
642

  
643
    entries = get_be32(pb);
644
    sc->sample_to_chunk_sz = entries;
645
    sc->sample_to_chunk = malloc(entries * sizeof(MOV_sample_to_chunk_tbl));
646
    for(i=0; i<entries; i++) {
647
        sc->sample_to_chunk[i].first = get_be32(pb);
648
        sc->sample_to_chunk[i].count = get_be32(pb);
649
        sc->sample_to_chunk[i].id = get_be32(pb);
650
#ifdef DEBUG
651
/*        printf("sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id); */
652
#endif
653
    }
654
    return 0;
655
}
656

  
657
static int parse_stsz(MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
658
{
659
    MOVContext *c;
660
    int entries, i;
661
    AVStream *st;
662
    MOVStreamContext *sc;
663
#ifdef DEBUG
664
    print_atom("stsz", atom_type, atom_offset, atom_size);
665
#endif
666
    c = (MOVContext *)param;
667
    st = c->fc->streams[c->fc->nb_streams-1];
668
    sc = (MOVStreamContext *)st->priv_data;
669
    
670
    get_byte(pb); /* version */
671
    get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
672
    
673
    sc->sample_size = get_be32(pb);
674
    entries = get_be32(pb);
675
    sc->sample_count = entries;
676
    printf("sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count);
677
    if(sc->sample_size)
678
        return 0; /* there isn't any table following */
679
    sc->sample_sizes = malloc(entries * sizeof(long));
680
    for(i=0; i<entries; i++) {
681
        sc->sample_sizes[i] = get_be32(pb);
682
#ifdef DEBUG
683
/*        printf("sample_sizes[]=%ld\n", sc->sample_sizes[i]); */
684
#endif
685
    }
686
    return 0;
687
}
688

  
689
static const MOVParseTableEntry mov_default_parse_table[] = {
690
/* mp4 atoms */
691
{ MKTAG( 'm', 'p', '4', 'a' ), parse_default },
692
{ MKTAG( 'c', 'o', '6', '4' ), parse_stco },
693
{ MKTAG( 's', 't', 'c', 'o' ), parse_stco },
694
{ MKTAG( 'c', 'r', 'h', 'd' ), parse_default },
695
{ MKTAG( 'c', 't', 't', 's' ), parse_leaf },
696
{ MKTAG( 'c', 'p', 'r', 't' ), parse_default },
697
{ MKTAG( 'u', 'r', 'l', ' ' ), parse_leaf },
698
{ MKTAG( 'u', 'r', 'n', ' ' ), parse_leaf },
699
{ MKTAG( 'd', 'i', 'n', 'f' ), parse_default },
700
{ MKTAG( 'd', 'r', 'e', 'f' ), parse_leaf },
701
{ MKTAG( 's', 't', 'd', 'p' ), parse_default },
702
{ MKTAG( 'e', 's', 'd', 's' ), parse_default },
703
{ MKTAG( 'e', 'd', 't', 's' ), parse_default },
704
{ MKTAG( 'e', 'l', 's', 't' ), parse_leaf },
705
{ MKTAG( 'u', 'u', 'i', 'd' ), parse_default },
706
{ MKTAG( 'f', 'r', 'e', 'e' ), parse_leaf },
707
{ MKTAG( 'h', 'd', 'l', 'r' ), parse_hdlr },
708
{ MKTAG( 'h', 'm', 'h', 'd' ), parse_default },
709
{ MKTAG( 'h', 'i', 'n', 't' ), parse_leaf },
710
{ MKTAG( 'n', 'm', 'h', 'd' ), parse_leaf },
711
{ MKTAG( 'm', 'p', '4', 's' ), parse_default },
712
{ MKTAG( 'm', 'd', 'i', 'a' ), parse_default },
713
{ MKTAG( 'm', 'd', 'a', 't' ), parse_mdat },
714
{ MKTAG( 'm', 'd', 'h', 'd' ), parse_leaf },
715
{ MKTAG( 'm', 'i', 'n', 'f' ), parse_default },
716
{ MKTAG( 'm', 'o', 'o', 'v' ), parse_moov },
717
{ MKTAG( 'm', 'v', 'h', 'd' ), parse_mvhd },
718
{ MKTAG( 'i', 'o', 'd', 's' ), parse_leaf },
719
{ MKTAG( 'o', 'd', 'h', 'd' ), parse_default },
720
{ MKTAG( 'm', 'p', 'o', 'd' ), parse_leaf },
721
{ MKTAG( 's', 't', 's', 'd' ), parse_stsd },
722
{ MKTAG( 's', 't', 's', 'z' ), parse_stsz },
723
{ MKTAG( 's', 't', 'b', 'l' ), parse_default },
724
{ MKTAG( 's', 't', 's', 'c' ), parse_stsc },
725
{ MKTAG( 's', 'd', 'h', 'd' ), parse_default },
726
{ MKTAG( 's', 't', 's', 'h' ), parse_default },
727
{ MKTAG( 's', 'k', 'i', 'p' ), parse_default },
728
{ MKTAG( 's', 'm', 'h', 'd' ), parse_leaf },
729
{ MKTAG( 'd', 'p', 'n', 'd' ), parse_leaf },
730
{ MKTAG( 's', 't', 's', 's' ), parse_leaf },
731
{ MKTAG( 's', 't', 't', 's' ), parse_leaf },
732
{ MKTAG( 't', 'r', 'a', 'k' ), parse_trak },
733
{ MKTAG( 't', 'k', 'h', 'd' ), parse_tkhd },
734
{ MKTAG( 't', 'r', 'e', 'f' ), parse_default }, /* not really */
735
{ MKTAG( 'u', 'd', 't', 'a' ), parse_leaf },
736
{ MKTAG( 'v', 'm', 'h', 'd' ), parse_leaf },
737
{ MKTAG( 'm', 'p', '4', 'v' ), parse_default },
738
/* extra mp4 */
739
{ MKTAG( 'M', 'D', 'E', 'S' ), parse_leaf },
740
/* QT atoms */
741
{ MKTAG( 'c', 'h', 'a', 'p' ), parse_leaf },
742
{ MKTAG( 'c', 'l', 'i', 'p' ), parse_default },
743
{ MKTAG( 'c', 'r', 'g', 'n' ), parse_leaf },
744
{ MKTAG( 'k', 'm', 'a', 't' ), parse_leaf },
745
{ MKTAG( 'm', 'a', 't', 't' ), parse_default },
746
{ MKTAG( 'r', 'd', 'r', 'f' ), parse_leaf },
747
{ MKTAG( 'r', 'm', 'd', 'a' ), parse_default },
748
{ MKTAG( 'r', 'm', 'd', 'r' ), parse_leaf },
749
//{ MKTAG( 'r', 'm', 'q', 'u' ), parse_leaf },
750
{ MKTAG( 'r', 'm', 'r', 'a' ), parse_default },
751
{ MKTAG( 's', 'c', 'p', 't' ), parse_leaf },
752
{ MKTAG( 's', 'y', 'n', 'c' ), parse_leaf },
753
{ MKTAG( 's', 's', 'r', 'c' ), parse_leaf },
754
{ MKTAG( 't', 'c', 'm', 'd' ), parse_leaf },
755
{ MKTAG( 'w', 'i', 'd', 'e' ), parse_leaf }, /* place holder */
756
{ 0L, parse_leaf }
757
};
758

  
759
static void mov_free_stream_context(MOVStreamContext *sc)
760
{
761
    if(sc) {
762
        if(sc->chunk_offsets)
763
            free(sc->chunk_offsets);
764
        if(sc->sample_to_chunk)
765
            free(sc->sample_to_chunk);
766
        free(sc);
767
    }
768
}
769

  
770
int mov_read_header(AVFormatContext *s, AVFormatParameters *ap)
771
{
772
    MOVContext *mov;
773
    ByteIOContext *pb = &s->pb;
774
    UINT32 tag, tag1;
775
    int i, j, nb, bps, err;
776
    INT64 size;
777
    AVStream *st;
778

  
779
    mov = malloc(sizeof(MOVContext));
780
    if (!mov)
781
        return -1;
782
    memset(mov, 0, sizeof(MOVContext));
783
    s->priv_data = mov;
784

  
785
    mov->fc = s;
786
    if(s->format->name[1] == 'p')
787
        mov->mp4 = 1;
788
    if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */
789
        size = url_filesize(url_fileno(pb));
790
    else
791
        size = 0x7FFFFFFFFFFFFFFF;
792

  
793
#ifdef DEBUG
794
    printf("filesz=%ld\n", size);
795
#endif
796

  
797
    /* check MOV header */
798
    err = parse_default(mov_default_parse_table, pb, 0L, 0LL, size, mov);
799
    if(err<0 || (!mov->found_moov || !mov->found_mdat)) {
800
        puts("header not found !!!");
801
        exit(1);
802
    }
803
#ifdef DEBUG
804
    printf("on_parse_exit_offset=%ld\n", url_ftell(pb));
805
#endif
806
    /* some cleanup : make sure we are on the mdat atom */
807
    if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset))
808
        url_fseek(pb, mov->mdat_offset, SEEK_SET);
809

  
810
    mov->next_chunk_offset = mov->mdat_offset; /* initialise reading */
811

  
812
#ifdef DEBUG
813
    printf("mdat_reset_offset=%ld\n", url_ftell(pb));
814
#endif
815

  
816
#ifdef DEBUG
817
    printf("streams= %ld\n", s->nb_streams);
818
#endif
819
    mov->total_streams = nb = s->nb_streams;
820
    
821
#if 1
822
    for(i=0; i<s->nb_streams;) {
823
        if(s->streams[i]->codec.codec_type == CODEC_TYPE_MOV_OTHER) {/* not audio, not video, delete */
824
            free(s->streams[i]);
825
            for(j=i+1; j<s->nb_streams; j++)
826
                s->streams[j-1] = s->streams[j];
827
            s->nb_streams--;
828
        } else
829
            i++;
830
    }
831
    for(i=0; i<s->nb_streams;i++) {
832
        MOVStreamContext *sc;
833
        sc = (MOVStreamContext *)s->streams[i]->priv_data;
834
        sc->ffindex = i;
835
        sc->is_ff_stream = 1;
836
    }
837
#endif
838
#ifdef DEBUG
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff