mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-26 19:01:44 +02:00
* Many, many changes to make it work (mostly). Information snagged from
staring at headers of real ASF files. ASFRecorder and avifile were other useful sources. Originally committed as revision 457 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
f359a5bed8
commit
f80c1ac01b
134
libav/asf.c
134
libav/asf.c
@ -19,6 +19,7 @@
|
|||||||
#include "avformat.h"
|
#include "avformat.h"
|
||||||
#include "avi.h"
|
#include "avi.h"
|
||||||
#include "tick.h"
|
#include "tick.h"
|
||||||
|
#include "mpegaudio.h"
|
||||||
|
|
||||||
#define PACKET_SIZE 3200
|
#define PACKET_SIZE 3200
|
||||||
#define PACKET_HEADER_SIZE 12
|
#define PACKET_HEADER_SIZE 12
|
||||||
@ -78,7 +79,9 @@ static const GUID audio_stream = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const GUID audio_conceal_none = {
|
static const GUID audio_conceal_none = {
|
||||||
0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
|
// 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
|
||||||
|
// New value lifted from avifile
|
||||||
|
0x20fb5700, 0x5b55, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GUID video_stream = {
|
static const GUID video_stream = {
|
||||||
@ -198,7 +201,7 @@ static void end_header(ByteIOContext *pb, INT64 pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* write an asf chunk (only used in streaming case) */
|
/* write an asf chunk (only used in streaming case) */
|
||||||
static void put_chunk(AVFormatContext *s, int type, int payload_length)
|
static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags)
|
||||||
{
|
{
|
||||||
ASFContext *asf = s->priv_data;
|
ASFContext *asf = s->priv_data;
|
||||||
ByteIOContext *pb = &s->pb;
|
ByteIOContext *pb = &s->pb;
|
||||||
@ -208,7 +211,7 @@ static void put_chunk(AVFormatContext *s, int type, int payload_length)
|
|||||||
put_le16(pb, type);
|
put_le16(pb, type);
|
||||||
put_le16(pb, length);
|
put_le16(pb, length);
|
||||||
put_le32(pb, asf->seqno);
|
put_le32(pb, asf->seqno);
|
||||||
put_le16(pb, 0); /* unknown bytes */
|
put_le16(pb, flags); /* unknown bytes */
|
||||||
put_le16(pb, length);
|
put_le16(pb, length);
|
||||||
asf->seqno++;
|
asf->seqno++;
|
||||||
}
|
}
|
||||||
@ -232,19 +235,27 @@ static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chu
|
|||||||
int has_title;
|
int has_title;
|
||||||
AVCodecContext *enc;
|
AVCodecContext *enc;
|
||||||
INT64 header_offset, cur_pos, hpos;
|
INT64 header_offset, cur_pos, hpos;
|
||||||
|
int bit_rate;
|
||||||
|
|
||||||
has_title = (s->title[0] != '\0');
|
has_title = (s->title[0] != '\0');
|
||||||
|
|
||||||
if (!url_is_streamed(&s->pb)) {
|
bit_rate = 0;
|
||||||
put_guid(pb, &asf_header);
|
for(n=0;n<s->nb_streams;n++) {
|
||||||
put_le64(pb, 0); /* header length, will be patched after */
|
enc = &s->streams[n]->codec;
|
||||||
put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */
|
|
||||||
put_byte(pb, 1); /* ??? */
|
bit_rate += enc->bit_rate;
|
||||||
put_byte(pb, 2); /* ??? */
|
|
||||||
} else {
|
|
||||||
put_chunk(s, 0x4824, 0); /* start of stream (length will be patched later) */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (url_is_streamed(&s->pb)) {
|
||||||
|
put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */
|
||||||
|
}
|
||||||
|
|
||||||
|
put_guid(pb, &asf_header);
|
||||||
|
put_le64(pb, 0); /* header length, will be patched after */
|
||||||
|
put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */
|
||||||
|
put_byte(pb, 1); /* ??? */
|
||||||
|
put_byte(pb, 2); /* ??? */
|
||||||
|
|
||||||
/* file header */
|
/* file header */
|
||||||
header_offset = url_ftell(pb);
|
header_offset = url_ftell(pb);
|
||||||
hpos = put_header(pb, &file_header);
|
hpos = put_header(pb, &file_header);
|
||||||
@ -260,7 +271,7 @@ static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chu
|
|||||||
put_le32(pb, url_is_streamed(&s->pb) ? 1 : 0); /* ??? */
|
put_le32(pb, url_is_streamed(&s->pb) ? 1 : 0); /* ??? */
|
||||||
put_le32(pb, asf->packet_size); /* packet size */
|
put_le32(pb, asf->packet_size); /* packet size */
|
||||||
put_le32(pb, asf->packet_size); /* packet size */
|
put_le32(pb, asf->packet_size); /* packet size */
|
||||||
put_le32(pb, 80 * asf->packet_size); /* frame_size ??? */
|
put_le32(pb, bit_rate); /* Nominal data rate in bps */
|
||||||
end_header(pb, hpos);
|
end_header(pb, hpos);
|
||||||
|
|
||||||
/* unknown headers */
|
/* unknown headers */
|
||||||
@ -287,7 +298,9 @@ static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chu
|
|||||||
|
|
||||||
/* stream headers */
|
/* stream headers */
|
||||||
for(n=0;n<s->nb_streams;n++) {
|
for(n=0;n<s->nb_streams;n++) {
|
||||||
|
INT64 es_pos;
|
||||||
ASFStream *stream = &asf->streams[n];
|
ASFStream *stream = &asf->streams[n];
|
||||||
|
|
||||||
enc = &s->streams[n]->codec;
|
enc = &s->streams[n]->codec;
|
||||||
asf->streams[n].num = n + 1;
|
asf->streams[n].num = n + 1;
|
||||||
asf->streams[n].seq = 0;
|
asf->streams[n].seq = 0;
|
||||||
@ -323,6 +336,7 @@ static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chu
|
|||||||
put_guid(pb, &video_conceal_none);
|
put_guid(pb, &video_conceal_none);
|
||||||
}
|
}
|
||||||
put_le64(pb, 0); /* ??? */
|
put_le64(pb, 0); /* ??? */
|
||||||
|
es_pos = url_ftell(pb);
|
||||||
put_le32(pb, extra_size); /* wav header len */
|
put_le32(pb, extra_size); /* wav header len */
|
||||||
put_le32(pb, extra_size2); /* additional data len */
|
put_le32(pb, extra_size2); /* additional data len */
|
||||||
put_le16(pb, n + 1); /* stream number */
|
put_le16(pb, n + 1); /* stream number */
|
||||||
@ -330,8 +344,16 @@ static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chu
|
|||||||
|
|
||||||
if (enc->codec_type == CODEC_TYPE_AUDIO) {
|
if (enc->codec_type == CODEC_TYPE_AUDIO) {
|
||||||
/* WAVEFORMATEX header */
|
/* WAVEFORMATEX header */
|
||||||
if (put_wav_header(pb, enc) < 0)
|
int wavsize = put_wav_header(pb, enc);
|
||||||
|
|
||||||
|
if (wavsize < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (wavsize != extra_size) {
|
||||||
|
cur_pos = url_ftell(pb);
|
||||||
|
url_fseek(pb, es_pos, SEEK_SET);
|
||||||
|
put_le32(pb, wavsize); /* wav header len */
|
||||||
|
url_fseek(pb, cur_pos, SEEK_SET);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
put_le32(pb, enc->width);
|
put_le32(pb, enc->width);
|
||||||
put_le32(pb, enc->height);
|
put_le32(pb, enc->height);
|
||||||
@ -370,17 +392,19 @@ static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chu
|
|||||||
|
|
||||||
cur_pos = url_ftell(pb);
|
cur_pos = url_ftell(pb);
|
||||||
header_size = cur_pos - header_offset;
|
header_size = cur_pos - header_offset;
|
||||||
if (!url_is_streamed(&s->pb)) {
|
if (url_is_streamed(&s->pb)) {
|
||||||
header_size += 24 + 6;
|
header_size += 8 + 30 + 50;
|
||||||
url_fseek(pb, header_offset - 14, SEEK_SET);
|
|
||||||
put_le64(pb, header_size);
|
url_fseek(pb, header_offset - 10 - 30, SEEK_SET);
|
||||||
} else {
|
|
||||||
header_size += 8 + 50;
|
|
||||||
url_fseek(pb, header_offset - 10, SEEK_SET);
|
|
||||||
put_le16(pb, header_size);
|
put_le16(pb, header_size);
|
||||||
url_fseek(pb, header_offset - 2, SEEK_SET);
|
url_fseek(pb, header_offset - 2 - 30, SEEK_SET);
|
||||||
put_le16(pb, header_size);
|
put_le16(pb, header_size);
|
||||||
|
|
||||||
|
header_size -= 8 + 30 + 50;
|
||||||
}
|
}
|
||||||
|
header_size += 24 + 6;
|
||||||
|
url_fseek(pb, header_offset - 14, SEEK_SET);
|
||||||
|
put_le64(pb, header_size);
|
||||||
url_fseek(pb, cur_pos, SEEK_SET);
|
url_fseek(pb, cur_pos, SEEK_SET);
|
||||||
|
|
||||||
/* movie chunk, followed by packets of packet_size */
|
/* movie chunk, followed by packets of packet_size */
|
||||||
@ -406,7 +430,7 @@ static int asf_write_header(AVFormatContext *s)
|
|||||||
asf->packet_size = PACKET_SIZE;
|
asf->packet_size = PACKET_SIZE;
|
||||||
asf->nb_packets = 0;
|
asf->nb_packets = 0;
|
||||||
|
|
||||||
if (asf_write_header1(s, 0, 24) < 0) {
|
if (asf_write_header1(s, 0, 50) < 0) {
|
||||||
free(asf);
|
free(asf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -424,7 +448,7 @@ static int asf_write_header(AVFormatContext *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* write a fixed size packet */
|
/* write a fixed size packet */
|
||||||
static void put_packet(AVFormatContext *s,
|
static int put_packet(AVFormatContext *s,
|
||||||
unsigned int timestamp, unsigned int duration,
|
unsigned int timestamp, unsigned int duration,
|
||||||
int nb_frames, int padsize)
|
int nb_frames, int padsize)
|
||||||
{
|
{
|
||||||
@ -433,7 +457,7 @@ static void put_packet(AVFormatContext *s,
|
|||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
if (url_is_streamed(&s->pb)) {
|
if (url_is_streamed(&s->pb)) {
|
||||||
put_chunk(s, 0x4424, asf->packet_size);
|
put_chunk(s, 0x4424, asf->packet_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
put_byte(pb, 0x82);
|
put_byte(pb, 0x82);
|
||||||
@ -449,12 +473,14 @@ static void put_packet(AVFormatContext *s,
|
|||||||
put_byte(pb, flags); /* flags */
|
put_byte(pb, flags); /* flags */
|
||||||
put_byte(pb, 0x5d);
|
put_byte(pb, 0x5d);
|
||||||
if (flags & 0x10)
|
if (flags & 0x10)
|
||||||
put_le16(pb, padsize);
|
put_le16(pb, padsize - 2);
|
||||||
if (flags & 0x08)
|
if (flags & 0x08)
|
||||||
put_byte(pb, padsize);
|
put_byte(pb, padsize - 1);
|
||||||
put_le32(pb, timestamp);
|
put_le32(pb, timestamp);
|
||||||
put_le16(pb, duration);
|
put_le16(pb, duration);
|
||||||
put_byte(pb, nb_frames | 0x80);
|
put_byte(pb, nb_frames | 0x80);
|
||||||
|
|
||||||
|
return PACKET_HEADER_SIZE + ((flags & 0x18) >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_packet(AVFormatContext *s)
|
static void flush_packet(AVFormatContext *s)
|
||||||
@ -462,24 +488,12 @@ static void flush_packet(AVFormatContext *s)
|
|||||||
ASFContext *asf = s->priv_data;
|
ASFContext *asf = s->priv_data;
|
||||||
int hdr_size, ptr;
|
int hdr_size, ptr;
|
||||||
|
|
||||||
put_packet(s, asf->packet_timestamp_start,
|
hdr_size = put_packet(s, asf->packet_timestamp_start,
|
||||||
asf->packet_timestamp_end - asf->packet_timestamp_start,
|
asf->packet_timestamp_end - asf->packet_timestamp_start,
|
||||||
asf->packet_nb_frames, asf->packet_size_left);
|
asf->packet_nb_frames, asf->packet_size_left);
|
||||||
|
|
||||||
/* compute padding */
|
/* Clear out the padding bytes */
|
||||||
hdr_size = PACKET_HEADER_SIZE;
|
ptr = asf->packet_size - hdr_size - asf->packet_size_left;
|
||||||
if (asf->packet_size_left > 0) {
|
|
||||||
/* if padding needed, don't forget to count the
|
|
||||||
padding byte in the header size */
|
|
||||||
hdr_size++;
|
|
||||||
asf->packet_size_left--;
|
|
||||||
/* XXX: I do not test again exact limit to avoid boundary problems */
|
|
||||||
if (asf->packet_size_left > 200) {
|
|
||||||
hdr_size++;
|
|
||||||
asf->packet_size_left--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ptr = asf->packet_size - PACKET_HEADER_SIZE - asf->packet_size_left;
|
|
||||||
memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
|
memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
|
||||||
|
|
||||||
put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
|
put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
|
||||||
@ -502,7 +516,7 @@ static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestam
|
|||||||
int val;
|
int val;
|
||||||
|
|
||||||
val = stream->num;
|
val = stream->num;
|
||||||
if (s->streams[val - 1]->codec.key_frame)
|
if (s->streams[val - 1]->codec.key_frame /* && frag_offset == 0 */)
|
||||||
val |= 0x80;
|
val |= 0x80;
|
||||||
put_byte(pb, val);
|
put_byte(pb, val);
|
||||||
put_byte(pb, stream->seq);
|
put_byte(pb, stream->seq);
|
||||||
@ -561,6 +575,7 @@ static int asf_write_packet(AVFormatContext *s, int stream_index,
|
|||||||
INT64 duration;
|
INT64 duration;
|
||||||
AVCodecContext *codec;
|
AVCodecContext *codec;
|
||||||
|
|
||||||
|
stream = &asf->streams[stream_index];
|
||||||
codec = &s->streams[stream_index]->codec;
|
codec = &s->streams[stream_index]->codec;
|
||||||
stream = &asf->streams[stream_index];
|
stream = &asf->streams[stream_index];
|
||||||
|
|
||||||
@ -590,7 +605,7 @@ static int asf_write_trailer(AVFormatContext *s)
|
|||||||
flush_packet(s);
|
flush_packet(s);
|
||||||
|
|
||||||
if (url_is_streamed(&s->pb)) {
|
if (url_is_streamed(&s->pb)) {
|
||||||
put_chunk(s, 0x4524, 0); /* end of stream */
|
put_chunk(s, 0x4524, 0, 0); /* end of stream */
|
||||||
} else {
|
} else {
|
||||||
/* rewrite an updated header */
|
/* rewrite an updated header */
|
||||||
file_size = url_ftell(&s->pb);
|
file_size = url_ftell(&s->pb);
|
||||||
@ -752,6 +767,26 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
|
|||||||
st->codec.codec_id = wav_codec_get_id(id, bps);
|
st->codec.codec_id = wav_codec_get_id(id, bps);
|
||||||
size = get_le16(pb);
|
size = get_le16(pb);
|
||||||
url_fskip(pb, size);
|
url_fskip(pb, size);
|
||||||
|
/* We have to init the frame size at some point .... */
|
||||||
|
switch (st->codec.codec_id) {
|
||||||
|
case CODEC_ID_MP3LAME:
|
||||||
|
st->codec.frame_size = MPA_FRAME_SIZE;
|
||||||
|
break;
|
||||||
|
case CODEC_ID_PCM_S16LE:
|
||||||
|
case CODEC_ID_PCM_S16BE:
|
||||||
|
case CODEC_ID_PCM_U16LE:
|
||||||
|
case CODEC_ID_PCM_U16BE:
|
||||||
|
case CODEC_ID_PCM_S8:
|
||||||
|
case CODEC_ID_PCM_U8:
|
||||||
|
case CODEC_ID_PCM_ALAW:
|
||||||
|
case CODEC_ID_PCM_MULAW:
|
||||||
|
st->codec.frame_size = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* This is probably wrong, but it prevents a crash later */
|
||||||
|
st->codec.frame_size = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
get_le32(pb);
|
get_le32(pb);
|
||||||
get_le32(pb);
|
get_le32(pb);
|
||||||
@ -879,6 +914,7 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
ASFStream *asf_st;
|
ASFStream *asf_st;
|
||||||
ByteIOContext *pb = &s->pb;
|
ByteIOContext *pb = &s->pb;
|
||||||
int ret, num, seq, frag_offset, payload_size, frag_len;
|
int ret, num, seq, frag_offset, payload_size, frag_len;
|
||||||
|
int key_frame;
|
||||||
int timestamp, i;
|
int timestamp, i;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
@ -892,7 +928,13 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
/* read frame header */
|
/* read frame header */
|
||||||
num = get_byte(pb) & 0x7f;
|
num = get_byte(pb);
|
||||||
|
if (num & 0x80)
|
||||||
|
key_frame = 1;
|
||||||
|
else
|
||||||
|
key_frame = 0;
|
||||||
|
|
||||||
|
num &= 0x7f;
|
||||||
seq = get_byte(pb);
|
seq = get_byte(pb);
|
||||||
frag_offset = get_le32(pb);
|
frag_offset = get_le32(pb);
|
||||||
get_byte(pb); /* flags */
|
get_byte(pb); /* flags */
|
||||||
@ -919,6 +961,10 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
/* new packet */
|
/* new packet */
|
||||||
av_new_packet(&asf_st->pkt, payload_size);
|
av_new_packet(&asf_st->pkt, payload_size);
|
||||||
asf_st->seq = seq;
|
asf_st->seq = seq;
|
||||||
|
if (key_frame)
|
||||||
|
asf_st->pkt.flags |= PKT_FLAG_KEY;
|
||||||
|
|
||||||
|
asf_st->pkt.pts = timestamp;
|
||||||
} else {
|
} else {
|
||||||
if (seq == asf_st->seq &&
|
if (seq == asf_st->seq &&
|
||||||
frag_offset == asf_st->frag_offset) {
|
frag_offset == asf_st->frag_offset) {
|
||||||
|
Loading…
Reference in New Issue
Block a user