* added some missing bits and removed obsolete files in ffmpeg-0.6
* replaced .. with $(DOTDOT) in Jamfiles * added __STDC_CONSTANT_MACROS define for C++ files (required for UINT64_C) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39537 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
f3ed9d3a45
commit
cf85a555b0
@ -9,6 +9,8 @@ SubDirHdrs [ FDirName $(SUBDIR) libavformat ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) libavutil ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) libswscale ] ;
|
||||
|
||||
SubDirC++Flags -D__STDC_CONSTANT_MACROS ;
|
||||
|
||||
Addon ffmpeg :
|
||||
AVCodecDecoder.cpp
|
||||
AVCodecEncoder.cpp
|
||||
|
@ -1,13 +1,13 @@
|
||||
SubDir HAIKU_TOP src add-ons media plugins ffmpeg libavcodec ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) .. ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(TARGET_ARCH) ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) .. libavutil ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) .. libswscale ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) .. libogg include ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) .. libtheora include ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) .. libvorbis include ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) .. libspeex include ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) libavutil ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) libswscale ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) libogg include ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) libtheora include ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) libvorbis include ] ;
|
||||
SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) libspeex include ] ;
|
||||
|
||||
|
||||
UseLibraryHeaders zlib ;
|
||||
|
@ -19,7 +19,6 @@ StaticLibrary libavformat.a :
|
||||
4xm.c
|
||||
adtsenc.c
|
||||
aea.c
|
||||
aiff.c
|
||||
aiffdec.c
|
||||
aiffenc.c
|
||||
allformats.c
|
||||
@ -148,9 +147,6 @@ StaticLibrary libavformat.a :
|
||||
rmenc.c
|
||||
rpl.c
|
||||
rtp.c
|
||||
rtp_aac.c
|
||||
rtp_h264.c
|
||||
rtp_mpv.c
|
||||
rtpdec.c
|
||||
rtpdec_amr.c
|
||||
rtpdec_asf.c
|
||||
|
@ -1,467 +0,0 @@
|
||||
/*
|
||||
* AIFF/AIFF-C muxer and demuxer
|
||||
* Copyright (c) 2006 Patrick Guimond
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/intfloat_readwrite.h"
|
||||
#include "avformat.h"
|
||||
#include "raw.h"
|
||||
#include "riff.h"
|
||||
|
||||
static const AVCodecTag codec_aiff_tags[] = {
|
||||
{ CODEC_ID_PCM_S16BE, MKTAG('N','O','N','E') },
|
||||
{ CODEC_ID_PCM_S8, MKTAG('N','O','N','E') },
|
||||
{ CODEC_ID_PCM_S24BE, MKTAG('N','O','N','E') },
|
||||
{ CODEC_ID_PCM_S32BE, MKTAG('N','O','N','E') },
|
||||
{ CODEC_ID_PCM_F32BE, MKTAG('f','l','3','2') },
|
||||
{ CODEC_ID_PCM_F64BE, MKTAG('f','l','6','4') },
|
||||
{ CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') },
|
||||
{ CODEC_ID_PCM_MULAW, MKTAG('u','l','a','w') },
|
||||
{ CODEC_ID_MACE3, MKTAG('M','A','C','3') },
|
||||
{ CODEC_ID_MACE6, MKTAG('M','A','C','6') },
|
||||
{ CODEC_ID_GSM, MKTAG('G','S','M',' ') },
|
||||
{ CODEC_ID_ADPCM_G726, MKTAG('G','7','2','6') },
|
||||
{ CODEC_ID_PCM_S16LE, MKTAG('s','o','w','t') },
|
||||
{ CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') },
|
||||
{ CODEC_ID_QDM2, MKTAG('Q','D','M','2') },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
#define AIFF 0
|
||||
#define AIFF_C_VERSION1 0xA2805140
|
||||
|
||||
static enum CodecID aiff_codec_get_id(int bps)
|
||||
{
|
||||
if (bps <= 8)
|
||||
return CODEC_ID_PCM_S8;
|
||||
if (bps <= 16)
|
||||
return CODEC_ID_PCM_S16BE;
|
||||
if (bps <= 24)
|
||||
return CODEC_ID_PCM_S24BE;
|
||||
if (bps <= 32)
|
||||
return CODEC_ID_PCM_S32BE;
|
||||
|
||||
/* bigger than 32 isn't allowed */
|
||||
return CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
/* returns the size of the found tag */
|
||||
static int get_tag(ByteIOContext *pb, uint32_t * tag)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (url_feof(pb))
|
||||
return AVERROR(EIO);
|
||||
|
||||
*tag = get_le32(pb);
|
||||
size = get_be32(pb);
|
||||
|
||||
if (size < 0)
|
||||
size = 0x7fffffff;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Metadata string read */
|
||||
static void get_meta(AVFormatContext *s, const char *key, int size)
|
||||
{
|
||||
uint8_t str[1024];
|
||||
int res = get_buffer(s->pb, str, FFMIN(sizeof(str)-1, size));
|
||||
if (res < 0)
|
||||
return;
|
||||
|
||||
str[res] = 0;
|
||||
if (size & 1)
|
||||
size++;
|
||||
size -= res;
|
||||
if (size)
|
||||
url_fskip(s->pb, size);
|
||||
|
||||
av_metadata_set(&s->metadata, key, str);
|
||||
}
|
||||
|
||||
/* Returns the number of sound data frames or negative on error */
|
||||
static unsigned int get_aiff_header(ByteIOContext *pb, AVCodecContext *codec,
|
||||
int size, unsigned version)
|
||||
{
|
||||
AVExtFloat ext;
|
||||
double sample_rate;
|
||||
unsigned int num_frames;
|
||||
|
||||
if (size & 1)
|
||||
size++;
|
||||
codec->codec_type = CODEC_TYPE_AUDIO;
|
||||
codec->channels = get_be16(pb);
|
||||
num_frames = get_be32(pb);
|
||||
codec->bits_per_coded_sample = get_be16(pb);
|
||||
|
||||
get_buffer(pb, (uint8_t*)&ext, sizeof(ext));/* Sample rate is in */
|
||||
sample_rate = av_ext2dbl(ext); /* 80 bits BE IEEE extended float */
|
||||
codec->sample_rate = sample_rate;
|
||||
size -= 18;
|
||||
|
||||
/* Got an AIFF-C? */
|
||||
if (version == AIFF_C_VERSION1) {
|
||||
codec->codec_tag = get_le32(pb);
|
||||
codec->codec_id = ff_codec_get_id(codec_aiff_tags, codec->codec_tag);
|
||||
|
||||
switch (codec->codec_id) {
|
||||
case CODEC_ID_PCM_S16BE:
|
||||
codec->codec_id = aiff_codec_get_id(codec->bits_per_coded_sample);
|
||||
codec->bits_per_coded_sample = av_get_bits_per_sample(codec->codec_id);
|
||||
break;
|
||||
case CODEC_ID_ADPCM_IMA_QT:
|
||||
codec->block_align = 34*codec->channels;
|
||||
codec->frame_size = 64;
|
||||
break;
|
||||
case CODEC_ID_MACE3:
|
||||
codec->block_align = 2*codec->channels;
|
||||
codec->frame_size = 6;
|
||||
break;
|
||||
case CODEC_ID_MACE6:
|
||||
codec->block_align = 1*codec->channels;
|
||||
codec->frame_size = 6;
|
||||
break;
|
||||
case CODEC_ID_GSM:
|
||||
codec->block_align = 33;
|
||||
codec->frame_size = 160;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
size -= 4;
|
||||
} else {
|
||||
/* Need the codec type */
|
||||
codec->codec_id = aiff_codec_get_id(codec->bits_per_coded_sample);
|
||||
codec->bits_per_coded_sample = av_get_bits_per_sample(codec->codec_id);
|
||||
}
|
||||
|
||||
/* Block align needs to be computed in all cases, as the definition
|
||||
* is specific to applications -> here we use the WAVE format definition */
|
||||
if (!codec->block_align)
|
||||
codec->block_align = (codec->bits_per_coded_sample * codec->channels) >> 3;
|
||||
|
||||
codec->bit_rate = (codec->frame_size ? codec->sample_rate/codec->frame_size :
|
||||
codec->sample_rate) * (codec->block_align << 3);
|
||||
|
||||
/* Chunk is over */
|
||||
if (size)
|
||||
url_fseek(pb, size, SEEK_CUR);
|
||||
|
||||
return num_frames;
|
||||
}
|
||||
|
||||
#if CONFIG_AIFF_MUXER
|
||||
typedef struct {
|
||||
int64_t form;
|
||||
int64_t frames;
|
||||
int64_t ssnd;
|
||||
} AIFFOutputContext;
|
||||
|
||||
static int aiff_write_header(AVFormatContext *s)
|
||||
{
|
||||
AIFFOutputContext *aiff = s->priv_data;
|
||||
ByteIOContext *pb = s->pb;
|
||||
AVCodecContext *enc = s->streams[0]->codec;
|
||||
AVExtFloat sample_rate;
|
||||
int aifc = 0;
|
||||
|
||||
/* First verify if format is ok */
|
||||
if (!enc->codec_tag)
|
||||
return -1;
|
||||
if (enc->codec_tag != MKTAG('N','O','N','E'))
|
||||
aifc = 1;
|
||||
|
||||
/* FORM AIFF header */
|
||||
put_tag(pb, "FORM");
|
||||
aiff->form = url_ftell(pb);
|
||||
put_be32(pb, 0); /* file length */
|
||||
put_tag(pb, aifc ? "AIFC" : "AIFF");
|
||||
|
||||
if (aifc) { // compressed audio
|
||||
enc->bits_per_coded_sample = 16;
|
||||
if (!enc->block_align) {
|
||||
av_log(s, AV_LOG_ERROR, "block align not set\n");
|
||||
return -1;
|
||||
}
|
||||
/* Version chunk */
|
||||
put_tag(pb, "FVER");
|
||||
put_be32(pb, 4);
|
||||
put_be32(pb, 0xA2805140);
|
||||
}
|
||||
|
||||
/* Common chunk */
|
||||
put_tag(pb, "COMM");
|
||||
put_be32(pb, aifc ? 24 : 18); /* size */
|
||||
put_be16(pb, enc->channels); /* Number of channels */
|
||||
|
||||
aiff->frames = url_ftell(pb);
|
||||
put_be32(pb, 0); /* Number of frames */
|
||||
|
||||
if (!enc->bits_per_coded_sample)
|
||||
enc->bits_per_coded_sample = av_get_bits_per_sample(enc->codec_id);
|
||||
if (!enc->bits_per_coded_sample) {
|
||||
av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n");
|
||||
return -1;
|
||||
}
|
||||
if (!enc->block_align)
|
||||
enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3;
|
||||
|
||||
put_be16(pb, enc->bits_per_coded_sample); /* Sample size */
|
||||
|
||||
sample_rate = av_dbl2ext((double)enc->sample_rate);
|
||||
put_buffer(pb, (uint8_t*)&sample_rate, sizeof(sample_rate));
|
||||
|
||||
if (aifc) {
|
||||
put_le32(pb, enc->codec_tag);
|
||||
put_be16(pb, 0);
|
||||
}
|
||||
|
||||
/* Sound data chunk */
|
||||
put_tag(pb, "SSND");
|
||||
aiff->ssnd = url_ftell(pb); /* Sound chunk size */
|
||||
put_be32(pb, 0); /* Sound samples data size */
|
||||
put_be32(pb, 0); /* Data offset */
|
||||
put_be32(pb, 0); /* Block-size (block align) */
|
||||
|
||||
av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
|
||||
|
||||
/* Data is starting here */
|
||||
put_flush_packet(pb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
ByteIOContext *pb = s->pb;
|
||||
put_buffer(pb, pkt->data, pkt->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aiff_write_trailer(AVFormatContext *s)
|
||||
{
|
||||
ByteIOContext *pb = s->pb;
|
||||
AIFFOutputContext *aiff = s->priv_data;
|
||||
AVCodecContext *enc = s->streams[0]->codec;
|
||||
|
||||
/* Chunks sizes must be even */
|
||||
int64_t file_size, end_size;
|
||||
end_size = file_size = url_ftell(pb);
|
||||
if (file_size & 1) {
|
||||
put_byte(pb, 0);
|
||||
end_size++;
|
||||
}
|
||||
|
||||
if (!url_is_streamed(s->pb)) {
|
||||
/* File length */
|
||||
url_fseek(pb, aiff->form, SEEK_SET);
|
||||
put_be32(pb, file_size - aiff->form - 4);
|
||||
|
||||
/* Number of sample frames */
|
||||
url_fseek(pb, aiff->frames, SEEK_SET);
|
||||
put_be32(pb, (file_size-aiff->ssnd-12)/enc->block_align);
|
||||
|
||||
/* Sound Data chunk size */
|
||||
url_fseek(pb, aiff->ssnd, SEEK_SET);
|
||||
put_be32(pb, file_size - aiff->ssnd - 4);
|
||||
|
||||
/* return to the end */
|
||||
url_fseek(pb, end_size, SEEK_SET);
|
||||
|
||||
put_flush_packet(pb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_AIFF_MUXER */
|
||||
|
||||
static int aiff_probe(AVProbeData *p)
|
||||
{
|
||||
/* check file header */
|
||||
if (p->buf[0] == 'F' && p->buf[1] == 'O' &&
|
||||
p->buf[2] == 'R' && p->buf[3] == 'M' &&
|
||||
p->buf[8] == 'A' && p->buf[9] == 'I' &&
|
||||
p->buf[10] == 'F' && (p->buf[11] == 'F' || p->buf[11] == 'C'))
|
||||
return AVPROBE_SCORE_MAX;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* aiff input */
|
||||
static int aiff_read_header(AVFormatContext *s,
|
||||
AVFormatParameters *ap)
|
||||
{
|
||||
int size, filesize;
|
||||
int64_t offset = 0;
|
||||
uint32_t tag;
|
||||
unsigned version = AIFF_C_VERSION1;
|
||||
ByteIOContext *pb = s->pb;
|
||||
AVStream * st;
|
||||
|
||||
/* check FORM header */
|
||||
filesize = get_tag(pb, &tag);
|
||||
if (filesize < 0 || tag != MKTAG('F', 'O', 'R', 'M'))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
/* AIFF data type */
|
||||
tag = get_le32(pb);
|
||||
if (tag == MKTAG('A', 'I', 'F', 'F')) /* Got an AIFF file */
|
||||
version = AIFF;
|
||||
else if (tag != MKTAG('A', 'I', 'F', 'C')) /* An AIFF-C file then */
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
filesize -= 4;
|
||||
|
||||
st = av_new_stream(s, 0);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
while (filesize > 0) {
|
||||
/* parse different chunks */
|
||||
size = get_tag(pb, &tag);
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
filesize -= size + 8;
|
||||
|
||||
switch (tag) {
|
||||
case MKTAG('C', 'O', 'M', 'M'): /* Common chunk */
|
||||
/* Then for the complete header info */
|
||||
st->nb_frames = get_aiff_header(pb, st->codec, size, version);
|
||||
if (st->nb_frames < 0)
|
||||
return st->nb_frames;
|
||||
if (offset > 0) // COMM is after SSND
|
||||
goto got_sound;
|
||||
break;
|
||||
case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */
|
||||
version = get_be32(pb);
|
||||
break;
|
||||
case MKTAG('N', 'A', 'M', 'E'): /* Sample name chunk */
|
||||
get_meta(s, "title" , size);
|
||||
break;
|
||||
case MKTAG('A', 'U', 'T', 'H'): /* Author chunk */
|
||||
get_meta(s, "author" , size);
|
||||
break;
|
||||
case MKTAG('(', 'c', ')', ' '): /* Copyright chunk */
|
||||
get_meta(s, "copyright", size);
|
||||
break;
|
||||
case MKTAG('A', 'N', 'N', 'O'): /* Annotation chunk */
|
||||
get_meta(s, "comment" , size);
|
||||
break;
|
||||
case MKTAG('S', 'S', 'N', 'D'): /* Sampled sound chunk */
|
||||
offset = get_be32(pb); /* Offset of sound data */
|
||||
get_be32(pb); /* BlockSize... don't care */
|
||||
offset += url_ftell(pb); /* Compute absolute data offset */
|
||||
if (st->codec->block_align) /* Assume COMM already parsed */
|
||||
goto got_sound;
|
||||
if (url_is_streamed(pb)) {
|
||||
av_log(s, AV_LOG_ERROR, "file is not seekable\n");
|
||||
return -1;
|
||||
}
|
||||
url_fskip(pb, size - 8);
|
||||
break;
|
||||
case MKTAG('w', 'a', 'v', 'e'):
|
||||
if ((uint64_t)size > (1<<30))
|
||||
return -1;
|
||||
st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!st->codec->extradata)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codec->extradata_size = size;
|
||||
get_buffer(pb, st->codec->extradata, size);
|
||||
break;
|
||||
default: /* Jump */
|
||||
if (size & 1) /* Always even aligned */
|
||||
size++;
|
||||
url_fskip (pb, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (!st->codec->block_align) {
|
||||
av_log(s, AV_LOG_ERROR, "could not find COMM tag\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
got_sound:
|
||||
/* Now positioned, get the sound data start and end */
|
||||
if (st->nb_frames)
|
||||
s->file_size = st->nb_frames * st->codec->block_align;
|
||||
|
||||
av_set_pts_info(st, 64, 1, st->codec->sample_rate);
|
||||
st->start_time = 0;
|
||||
st->duration = st->codec->frame_size ?
|
||||
st->nb_frames * st->codec->frame_size : st->nb_frames;
|
||||
|
||||
/* Position the stream at the first block */
|
||||
url_fseek(pb, offset, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_SIZE 4096
|
||||
|
||||
static int aiff_read_packet(AVFormatContext *s,
|
||||
AVPacket *pkt)
|
||||
{
|
||||
AVStream *st = s->streams[0];
|
||||
int res;
|
||||
|
||||
/* End of stream may be reached */
|
||||
if (url_feof(s->pb))
|
||||
return AVERROR(EIO);
|
||||
|
||||
/* Now for that packet */
|
||||
res = av_get_packet(s->pb, pkt, (MAX_SIZE / st->codec->block_align) * st->codec->block_align);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
/* Only one stream in an AIFF file */
|
||||
pkt->stream_index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_AIFF_DEMUXER
|
||||
AVInputFormat aiff_demuxer = {
|
||||
"aiff",
|
||||
NULL_IF_CONFIG_SMALL("Audio IFF"),
|
||||
0,
|
||||
aiff_probe,
|
||||
aiff_read_header,
|
||||
aiff_read_packet,
|
||||
NULL,
|
||||
pcm_read_seek,
|
||||
.codec_tag= (const AVCodecTag* const []){codec_aiff_tags, 0},
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_AIFF_MUXER
|
||||
AVOutputFormat aiff_muxer = {
|
||||
"aiff",
|
||||
NULL_IF_CONFIG_SMALL("Audio IFF"),
|
||||
"audio/aiff",
|
||||
"aif,aiff,afc,aifc",
|
||||
sizeof(AIFFOutputContext),
|
||||
CODEC_ID_PCM_S16BE,
|
||||
CODEC_ID_NONE,
|
||||
aiff_write_header,
|
||||
aiff_write_packet,
|
||||
aiff_write_trailer,
|
||||
.codec_tag= (const AVCodecTag* const []){codec_aiff_tags, 0},
|
||||
};
|
||||
#endif
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* copyright (c) 2007 Luca Abeni
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "avformat.h"
|
||||
#include "rtpenc.h"
|
||||
|
||||
|
||||
void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size)
|
||||
{
|
||||
RTPMuxContext *s = s1->priv_data;
|
||||
int len, max_packet_size;
|
||||
uint8_t *p;
|
||||
const int max_frames_per_packet = s->max_frames_per_packet ? s->max_frames_per_packet : 5;
|
||||
const int max_au_headers_size = 2 + 2 * max_frames_per_packet;
|
||||
|
||||
/* skip ADTS header, if present */
|
||||
if ((s1->streams[0]->codec->extradata_size) == 0) {
|
||||
size -= 7;
|
||||
buff += 7;
|
||||
}
|
||||
max_packet_size = s->max_payload_size - max_au_headers_size;
|
||||
|
||||
/* test if the packet must be sent */
|
||||
len = (s->buf_ptr - s->buf);
|
||||
if ((s->num_frames == max_frames_per_packet) || (len && (len + size) > s->max_payload_size)) {
|
||||
int au_size = s->num_frames * 2;
|
||||
|
||||
p = s->buf + max_au_headers_size - au_size - 2;
|
||||
if (p != s->buf) {
|
||||
memmove(p + 2, s->buf + 2, au_size);
|
||||
}
|
||||
/* Write the AU header size */
|
||||
p[0] = ((au_size * 8) & 0xFF) >> 8;
|
||||
p[1] = (au_size * 8) & 0xFF;
|
||||
|
||||
ff_rtp_send_data(s1, p, s->buf_ptr - p, 1);
|
||||
|
||||
s->num_frames = 0;
|
||||
}
|
||||
if (s->num_frames == 0) {
|
||||
s->buf_ptr = s->buf + max_au_headers_size;
|
||||
s->timestamp = s->cur_timestamp;
|
||||
}
|
||||
|
||||
if (size <= max_packet_size) {
|
||||
p = s->buf + s->num_frames++ * 2 + 2;
|
||||
*p++ = size >> 5;
|
||||
*p = (size & 0x1F) << 3;
|
||||
memcpy(s->buf_ptr, buff, size);
|
||||
s->buf_ptr += size;
|
||||
} else {
|
||||
int au_size = size;
|
||||
|
||||
max_packet_size = s->max_payload_size - 4;
|
||||
p = s->buf;
|
||||
p[0] = 0;
|
||||
p[1] = 16;
|
||||
while (size > 0) {
|
||||
len = FFMIN(size, max_packet_size);
|
||||
p[2] = au_size >> 5;
|
||||
p[3] = (au_size & 0x1F) << 3;
|
||||
memcpy(p + 4, buff, len);
|
||||
ff_rtp_send_data(s1, p, len + 4, len == size);
|
||||
size -= len;
|
||||
buff += len;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* RTP packetization for AMR audio
|
||||
* Copyright (c) 2007 Luca Abeni
|
||||
* Copyright (c) 2009 Martin Storsjo
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "avformat.h"
|
||||
#include "rtpenc.h"
|
||||
|
||||
/**
|
||||
* Packetize AMR frames into RTP packets according to RFC 3267,
|
||||
* in octet-aligned mode.
|
||||
*/
|
||||
void ff_rtp_send_amr(AVFormatContext *s1, const uint8_t *buff, int size)
|
||||
{
|
||||
RTPMuxContext *s = s1->priv_data;
|
||||
int max_header_toc_size = 1 + s->max_frames_per_packet;
|
||||
uint8_t *p;
|
||||
int len;
|
||||
|
||||
/* Test if the packet must be sent. */
|
||||
len = s->buf_ptr - s->buf;
|
||||
if (s->num_frames == s->max_frames_per_packet || (len && len + size - 1 > s->max_payload_size)) {
|
||||
int header_size = s->num_frames + 1;
|
||||
p = s->buf + max_header_toc_size - header_size;
|
||||
if (p != s->buf)
|
||||
memmove(p, s->buf, header_size);
|
||||
|
||||
ff_rtp_send_data(s1, p, s->buf_ptr - p, 1);
|
||||
|
||||
s->num_frames = 0;
|
||||
}
|
||||
|
||||
if (!s->num_frames) {
|
||||
s->buf[0] = 0xf0;
|
||||
s->buf_ptr = s->buf + max_header_toc_size;
|
||||
s->timestamp = s->cur_timestamp;
|
||||
} else {
|
||||
/* Mark the previous TOC entry as having more entries following. */
|
||||
s->buf[1 + s->num_frames - 1] |= 0x80;
|
||||
}
|
||||
|
||||
/* Copy the frame type and quality bits. */
|
||||
s->buf[1 + s->num_frames++] = buff[0] & 0x7C;
|
||||
buff++;
|
||||
size--;
|
||||
memcpy(s->buf_ptr, buff, size);
|
||||
s->buf_ptr += size;
|
||||
}
|
||||
|
@ -1,281 +0,0 @@
|
||||
/*
|
||||
* Microsoft RTP/ASF support.
|
||||
* Copyright (c) 2008 Ronald S. Bultje
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file libavformat/rtp_asf.c
|
||||
* @brief Microsoft RTP/ASF support
|
||||
* @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
*/
|
||||
|
||||
#include <libavutil/base64.h>
|
||||
#include <libavutil/avstring.h>
|
||||
#include <libavutil/intreadwrite.h>
|
||||
#include "rtp.h"
|
||||
#include "rtp_asf.h"
|
||||
#include "rtsp.h"
|
||||
#include "asf.h"
|
||||
|
||||
/**
|
||||
* From MSDN 2.2.1.4, we learn that ASF data packets over RTP should not
|
||||
* contain any padding. Unfortunately, the header min/max_pktsize are not
|
||||
* updated (thus making min_pktsize invalid). Here, we "fix" these faulty
|
||||
* min_pktsize values in the ASF file header.
|
||||
* @return 0 on success, <0 on failure (currently -1).
|
||||
*/
|
||||
static int rtp_asf_fix_header(uint8_t *buf, int len)
|
||||
{
|
||||
uint8_t *p = buf, *end = buf + len;
|
||||
|
||||
if (len < sizeof(ff_asf_guid) * 2 + 22 ||
|
||||
memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) {
|
||||
return -1;
|
||||
}
|
||||
p += sizeof(ff_asf_guid) + 14;
|
||||
do {
|
||||
uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid));
|
||||
if (memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
|
||||
if (chunksize > end - p)
|
||||
return -1;
|
||||
p += chunksize;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip most of the file header, to min_pktsize */
|
||||
p += 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2;
|
||||
if (p + 8 <= end && AV_RL32(p) == AV_RL32(p + 4)) {
|
||||
/* and set that to zero */
|
||||
AV_WL32(p, 0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
} while (end - p >= sizeof(ff_asf_guid) + 8);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following code is basically a buffered ByteIOContext,
|
||||
* with the added benefit of returning -EAGAIN (instead of 0)
|
||||
* on packet boundaries, such that the ASF demuxer can return
|
||||
* safely and resume business at the next packet.
|
||||
*/
|
||||
static int packetizer_read(void *opaque, uint8_t *buf, int buf_size)
|
||||
{
|
||||
return AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
static void init_packetizer(ByteIOContext *pb, uint8_t *buf, int len)
|
||||
{
|
||||
init_put_byte(pb, buf, len, 0, NULL, packetizer_read, NULL, NULL);
|
||||
|
||||
/* this "fills" the buffer with its current content */
|
||||
pb->pos = len;
|
||||
pb->buf_end = buf + len;
|
||||
}
|
||||
|
||||
void ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p)
|
||||
{
|
||||
if (av_strstart(p, "pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,", &p)) {
|
||||
ByteIOContext pb;
|
||||
RTSPState *rt = s->priv_data;
|
||||
int len = strlen(p) * 6 / 8;
|
||||
char *buf = av_mallocz(len);
|
||||
av_base64_decode(buf, p, len);
|
||||
|
||||
if (rtp_asf_fix_header(buf, len) < 0)
|
||||
av_log(s, AV_LOG_ERROR,
|
||||
"Failed to fix invalid RTSP-MS/ASF min_pktsize\n");
|
||||
init_packetizer(&pb, buf, len);
|
||||
if (rt->asf_ctx) {
|
||||
av_close_input_stream(rt->asf_ctx);
|
||||
rt->asf_ctx = NULL;
|
||||
}
|
||||
av_open_input_stream(&rt->asf_ctx, &pb, "", &asf_demuxer, NULL);
|
||||
rt->asf_pb_pos = url_ftell(&pb);
|
||||
av_free(buf);
|
||||
rt->asf_ctx->pb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index,
|
||||
PayloadContext *asf, const char *line)
|
||||
{
|
||||
if (av_strstart(line, "stream:", &line)) {
|
||||
RTSPState *rt = s->priv_data;
|
||||
|
||||
s->streams[stream_index]->id = strtol(line, NULL, 10);
|
||||
|
||||
if (rt->asf_ctx) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rt->asf_ctx->nb_streams; i++) {
|
||||
if (s->streams[stream_index]->id == rt->asf_ctx->streams[i]->id) {
|
||||
*s->streams[stream_index]->codec =
|
||||
*rt->asf_ctx->streams[i]->codec;
|
||||
rt->asf_ctx->streams[i]->codec->extradata_size = 0;
|
||||
rt->asf_ctx->streams[i]->codec->extradata = NULL;
|
||||
av_set_pts_info(s->streams[stream_index], 32, 1, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct PayloadContext {
|
||||
ByteIOContext *pktbuf, pb;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return 0 when a packet was written into /p pkt, and no more data is left;
|
||||
* 1 when a packet was written into /p pkt, and more packets might be left;
|
||||
* <0 when not enough data was provided to return a full packet, or on error.
|
||||
*/
|
||||
static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf,
|
||||
AVStream *st, AVPacket *pkt,
|
||||
uint32_t *timestamp,
|
||||
const uint8_t *buf, int len, int flags)
|
||||
{
|
||||
ByteIOContext *pb = &asf->pb;
|
||||
int res, mflags, len_off;
|
||||
RTSPState *rt = s->priv_data;
|
||||
|
||||
if (!rt->asf_ctx)
|
||||
return -1;
|
||||
|
||||
if (len > 0) {
|
||||
int off, out_len;
|
||||
|
||||
if (len < 4)
|
||||
return -1;
|
||||
|
||||
init_put_byte(pb, buf, len, 0, NULL, NULL, NULL, NULL);
|
||||
mflags = get_byte(pb);
|
||||
if (mflags & 0x80)
|
||||
flags |= RTP_FLAG_KEY;
|
||||
len_off = get_be24(pb);
|
||||
if (mflags & 0x20) /**< relative timestamp */
|
||||
url_fskip(pb, 4);
|
||||
if (mflags & 0x10) /**< has duration */
|
||||
url_fskip(pb, 4);
|
||||
if (mflags & 0x8) /**< has location ID */
|
||||
url_fskip(pb, 4);
|
||||
off = url_ftell(pb);
|
||||
|
||||
av_freep(&asf->buf);
|
||||
if (!(mflags & 0x40)) {
|
||||
/**
|
||||
* If 0x40 is not set, the len_off field specifies an offset of this
|
||||
* packet's payload data in the complete (reassembled) ASF packet.
|
||||
* This is used to spread one ASF packet over multiple RTP packets.
|
||||
*/
|
||||
if (asf->pktbuf && len_off != url_ftell(asf->pktbuf)) {
|
||||
uint8_t *p;
|
||||
url_close_dyn_buf(asf->pktbuf, &p);
|
||||
asf->pktbuf = NULL;
|
||||
av_free(p);
|
||||
}
|
||||
if (!len_off && !asf->pktbuf &&
|
||||
!(res = url_open_dyn_packet_buf(&asf->pktbuf, rt->asf_ctx->packet_size)))
|
||||
return res;
|
||||
if (!asf->pktbuf)
|
||||
return AVERROR(EIO);
|
||||
|
||||
put_buffer(asf->pktbuf, buf + off, len - off);
|
||||
if (!(flags & RTP_FLAG_MARKER))
|
||||
return -1;
|
||||
out_len = url_close_dyn_buf(asf->pktbuf, &asf->buf);
|
||||
asf->pktbuf = NULL;
|
||||
} else {
|
||||
/**
|
||||
* If 0x40 is set, the len_off field specifies the length of the
|
||||
* next ASF packet that can be read from this payload data alone.
|
||||
* This is commonly the same as the payload size, but could be
|
||||
* less in case of packet splitting (i.e. multiple ASF packets in
|
||||
* one RTP packet).
|
||||
*/
|
||||
if (len_off != len) {
|
||||
av_log_missing_feature(s,
|
||||
"RTSP-MS packet splitting", 1);
|
||||
return -1;
|
||||
}
|
||||
asf->buf = av_malloc(len - off);
|
||||
out_len = len - off;
|
||||
memcpy(asf->buf, buf + off, len - off);
|
||||
}
|
||||
|
||||
init_packetizer(pb, asf->buf, out_len);
|
||||
pb->pos += rt->asf_pb_pos;
|
||||
pb->eof_reached = 0;
|
||||
rt->asf_ctx->pb = pb;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int i;
|
||||
|
||||
res = av_read_packet(rt->asf_ctx, pkt);
|
||||
rt->asf_pb_pos = url_ftell(pb);
|
||||
if (res != 0)
|
||||
break;
|
||||
for (i = 0; i < s->nb_streams; i++) {
|
||||
if (s->streams[i]->id == rt->asf_ctx->streams[pkt->stream_index]->id) {
|
||||
pkt->stream_index = i;
|
||||
return 1; // FIXME: return 0 if last packet
|
||||
}
|
||||
}
|
||||
av_free_packet(pkt);
|
||||
}
|
||||
|
||||
return res == 1 ? -1 : res;
|
||||
}
|
||||
|
||||
static PayloadContext *asfrtp_new_context(void)
|
||||
{
|
||||
return av_mallocz(sizeof(PayloadContext));
|
||||
}
|
||||
|
||||
static void asfrtp_free_context(PayloadContext *asf)
|
||||
{
|
||||
if (asf->pktbuf) {
|
||||
uint8_t *p = NULL;
|
||||
url_close_dyn_buf(asf->pktbuf, &p);
|
||||
asf->pktbuf = NULL;
|
||||
av_free(p);
|
||||
}
|
||||
av_freep(&asf->buf);
|
||||
av_free(asf);
|
||||
}
|
||||
|
||||
#define RTP_ASF_HANDLER(n, s, t) \
|
||||
RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \
|
||||
.enc_name = s, \
|
||||
.codec_type = t, \
|
||||
.codec_id = CODEC_ID_NONE, \
|
||||
.parse_sdp_a_line = asfrtp_parse_sdp_line, \
|
||||
.open = asfrtp_new_context, \
|
||||
.close = asfrtp_free_context, \
|
||||
.parse_packet = asfrtp_parse_packet, \
|
||||
};
|
||||
|
||||
RTP_ASF_HANDLER(asf_pfv, "x-asf-pf", CODEC_TYPE_VIDEO);
|
||||
RTP_ASF_HANDLER(asf_pfa, "x-asf-pf", CODEC_TYPE_AUDIO);
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Microsoft RTP/ASF support.
|
||||
* Copyright (c) 2008 Ronald S. Bultje
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_RTP_ASF_H
|
||||
#define AVFORMAT_RTP_ASF_H
|
||||
|
||||
#include "avformat.h"
|
||||
#include "rtpdec.h"
|
||||
|
||||
/**
|
||||
* Parse a Windows Media Server-specific SDP line
|
||||
*
|
||||
* @param s RTSP demux context
|
||||
* @param line the SDP line to be parsed
|
||||
*/
|
||||
void ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p);
|
||||
|
||||
/**
|
||||
* Handlers for the x-asf-pf payloads (the payload ID for RTP/ASF).
|
||||
* Defined and implemented in rtp_asf.c, registered in rtpdec.c.
|
||||
*/
|
||||
extern RTPDynamicProtocolHandler ff_ms_rtp_asf_pfv_handler,
|
||||
ff_ms_rtp_asf_pfa_handler;
|
||||
|
||||
#endif /* AVFORMAT_RTP_ASF_H */
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* RTP packetization for H.263 video
|
||||
* Copyright (c) 2009 Luca Abeni
|
||||
* Copyright (c) 2009 Martin Storsjo
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "avformat.h"
|
||||
#include "rtpenc.h"
|
||||
|
||||
static const uint8_t *find_resync_marker_reverse(const uint8_t *restrict start,
|
||||
const uint8_t *restrict end)
|
||||
{
|
||||
const uint8_t *p = end - 1;
|
||||
start += 1; /* Make sure we never return the original start. */
|
||||
for (; p > start; p -= 2) {
|
||||
if (!*p) {
|
||||
if (!p[ 1] && p[2]) return p;
|
||||
else if (!p[-1] && p[1]) return p - 1;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Packetize H.263 frames into RTP packets according to RFC 4629
|
||||
*/
|
||||
void ff_rtp_send_h263(AVFormatContext *s1, const uint8_t *buf1, int size)
|
||||
{
|
||||
RTPMuxContext *s = s1->priv_data;
|
||||
int len, max_packet_size;
|
||||
uint8_t *q;
|
||||
|
||||
max_packet_size = s->max_payload_size;
|
||||
|
||||
while (size > 0) {
|
||||
q = s->buf;
|
||||
if ((buf1[0] == 0) && (buf1[1] == 0)) {
|
||||
*q++ = 0x04;
|
||||
buf1 += 2;
|
||||
size -= 2;
|
||||
} else {
|
||||
*q++ = 0;
|
||||
}
|
||||
*q++ = 0;
|
||||
|
||||
len = FFMIN(max_packet_size - 2, size);
|
||||
|
||||
/* Look for a better place to split the frame into packets. */
|
||||
if (len < size) {
|
||||
const uint8_t *end = find_resync_marker_reverse(buf1, buf1 + len);
|
||||
len = end - buf1;
|
||||
}
|
||||
|
||||
memcpy(q, buf1, len);
|
||||
q += len;
|
||||
|
||||
/* 90 KHz time stamp */
|
||||
s->timestamp = s->cur_timestamp;
|
||||
ff_rtp_send_data(s1, s->buf, q - s->buf, (len == size));
|
||||
|
||||
buf1 += len;
|
||||
size -= len;
|
||||
}
|
||||
}
|
@ -1,416 +0,0 @@
|
||||
/*
|
||||
* RTP H264 Protocol (RFC3984)
|
||||
* Copyright (c) 2006 Ryan Martell
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file libavformat/rtp_h264.c
|
||||
* @brief H.264 / RTP Code (RFC3984)
|
||||
* @author Ryan Martell <rdm4@martellventures.com>
|
||||
*
|
||||
* @note Notes:
|
||||
* Notes:
|
||||
* This currently supports packetization mode:
|
||||
* Single Nal Unit Mode (0), or
|
||||
* Non-Interleaved Mode (1). It currently does not support
|
||||
* Interleaved Mode (2). (This requires implementing STAP-B, MTAP16, MTAP24, FU-B packet types)
|
||||
*
|
||||
* @note TODO:
|
||||
* 1) RTCP sender reports for udp streams are required..
|
||||
*
|
||||
*/
|
||||
|
||||
#include "libavutil/base64.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavcodec/get_bits.h"
|
||||
#include "avformat.h"
|
||||
#include "mpegts.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include "network.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include "rtpdec.h"
|
||||
#include "rtp_h264.h"
|
||||
|
||||
/**
|
||||
RTP/H264 specific private data.
|
||||
*/
|
||||
struct PayloadContext {
|
||||
unsigned long cookie; ///< sanity check, to make sure we get the pointer we're expecting.
|
||||
|
||||
//sdp setup parameters
|
||||
uint8_t profile_idc; ///< from the sdp setup parameters.
|
||||
uint8_t profile_iop; ///< from the sdp setup parameters.
|
||||
uint8_t level_idc; ///< from the sdp setup parameters.
|
||||
int packetization_mode; ///< from the sdp setup parameters.
|
||||
#ifdef DEBUG
|
||||
int packet_types_received[32];
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MAGIC_COOKIE (0xdeadbeef) ///< Cookie for the extradata; to verify we are what we think we are, and that we haven't been freed.
|
||||
#define DEAD_COOKIE (0xdeaddead) ///< Cookie for the extradata; once it is freed.
|
||||
|
||||
/* ---------------- private code */
|
||||
static void sdp_parse_fmtp_config_h264(AVStream * stream,
|
||||
PayloadContext * h264_data,
|
||||
char *attr, char *value)
|
||||
{
|
||||
AVCodecContext *codec = stream->codec;
|
||||
assert(codec->codec_id == CODEC_ID_H264);
|
||||
assert(h264_data != NULL);
|
||||
|
||||
if (!strcmp(attr, "packetization-mode")) {
|
||||
av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
|
||||
h264_data->packetization_mode = atoi(value);
|
||||
/*
|
||||
Packetization Mode:
|
||||
0 or not present: Single NAL mode (Only nals from 1-23 are allowed)
|
||||
1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed.
|
||||
2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A), and 29 (FU-B) are allowed.
|
||||
*/
|
||||
if (h264_data->packetization_mode > 1)
|
||||
av_log(codec, AV_LOG_ERROR,
|
||||
"Interleaved RTP mode is not supported yet.");
|
||||
} else if (!strcmp(attr, "profile-level-id")) {
|
||||
if (strlen(value) == 6) {
|
||||
char buffer[3];
|
||||
// 6 characters=3 bytes, in hex.
|
||||
uint8_t profile_idc;
|
||||
uint8_t profile_iop;
|
||||
uint8_t level_idc;
|
||||
|
||||
buffer[0] = value[0]; buffer[1] = value[1]; buffer[2] = '\0';
|
||||
profile_idc = strtol(buffer, NULL, 16);
|
||||
buffer[0] = value[2]; buffer[1] = value[3];
|
||||
profile_iop = strtol(buffer, NULL, 16);
|
||||
buffer[0] = value[4]; buffer[1] = value[5];
|
||||
level_idc = strtol(buffer, NULL, 16);
|
||||
|
||||
// set the parameters...
|
||||
av_log(codec, AV_LOG_DEBUG,
|
||||
"RTP Profile IDC: %x Profile IOP: %x Level: %x\n",
|
||||
profile_idc, profile_iop, level_idc);
|
||||
h264_data->profile_idc = profile_idc;
|
||||
h264_data->profile_iop = profile_iop;
|
||||
h264_data->level_idc = level_idc;
|
||||
}
|
||||
} else if (!strcmp(attr, "sprop-parameter-sets")) {
|
||||
uint8_t start_sequence[]= { 0, 0, 1 };
|
||||
codec->extradata_size= 0;
|
||||
codec->extradata= NULL;
|
||||
|
||||
while (*value) {
|
||||
char base64packet[1024];
|
||||
uint8_t decoded_packet[1024];
|
||||
uint32_t packet_size;
|
||||
char *dst = base64packet;
|
||||
|
||||
while (*value && *value != ','
|
||||
&& (dst - base64packet) < sizeof(base64packet) - 1) {
|
||||
*dst++ = *value++;
|
||||
}
|
||||
*dst++ = '\0';
|
||||
|
||||
if (*value == ',')
|
||||
value++;
|
||||
|
||||
packet_size= av_base64_decode(decoded_packet, base64packet, sizeof(decoded_packet));
|
||||
if (packet_size) {
|
||||
uint8_t *dest= av_malloc(packet_size+sizeof(start_sequence)+codec->extradata_size);
|
||||
if(dest)
|
||||
{
|
||||
if(codec->extradata_size)
|
||||
{
|
||||
// av_realloc?
|
||||
memcpy(dest, codec->extradata, codec->extradata_size);
|
||||
av_free(codec->extradata);
|
||||
}
|
||||
|
||||
memcpy(dest+codec->extradata_size, start_sequence, sizeof(start_sequence));
|
||||
memcpy(dest+codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size);
|
||||
|
||||
codec->extradata= dest;
|
||||
codec->extradata_size+= sizeof(start_sequence)+packet_size;
|
||||
} else {
|
||||
av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!");
|
||||
}
|
||||
}
|
||||
}
|
||||
av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!", codec->extradata, codec->extradata_size);
|
||||
}
|
||||
}
|
||||
|
||||
// return 0 on packet, no more left, 1 on packet, 1 on partial packet...
|
||||
static int h264_handle_packet(AVFormatContext *ctx,
|
||||
PayloadContext *data,
|
||||
AVStream *st,
|
||||
AVPacket * pkt,
|
||||
uint32_t * timestamp,
|
||||
const uint8_t * buf,
|
||||
int len, int flags)
|
||||
{
|
||||
uint8_t nal = buf[0];
|
||||
uint8_t type = (nal & 0x1f);
|
||||
int result= 0;
|
||||
uint8_t start_sequence[]= {0, 0, 1};
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(data);
|
||||
assert(data->cookie == MAGIC_COOKIE);
|
||||
#endif
|
||||
assert(buf);
|
||||
|
||||
if (type >= 1 && type <= 23)
|
||||
type = 1; // simplify the case. (these are all the nal types used internally by the h264 codec)
|
||||
switch (type) {
|
||||
case 0: // undefined;
|
||||
result= -1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
av_new_packet(pkt, len+sizeof(start_sequence));
|
||||
memcpy(pkt->data, start_sequence, sizeof(start_sequence));
|
||||
memcpy(pkt->data+sizeof(start_sequence), buf, len);
|
||||
#ifdef DEBUG
|
||||
data->packet_types_received[nal & 0x1f]++;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 24: // STAP-A (one packet, multiple nals)
|
||||
// consume the STAP-A NAL
|
||||
buf++;
|
||||
len--;
|
||||
// first we are going to figure out the total size....
|
||||
{
|
||||
int pass= 0;
|
||||
int total_length= 0;
|
||||
uint8_t *dst= NULL;
|
||||
|
||||
for(pass= 0; pass<2; pass++) {
|
||||
const uint8_t *src= buf;
|
||||
int src_len= len;
|
||||
|
||||
do {
|
||||
uint16_t nal_size = AV_RB16(src); // this going to be a problem if unaligned (can it be?)
|
||||
|
||||
// consume the length of the aggregate...
|
||||
src += 2;
|
||||
src_len -= 2;
|
||||
|
||||
if (nal_size <= src_len) {
|
||||
if(pass==0) {
|
||||
// counting...
|
||||
total_length+= sizeof(start_sequence)+nal_size;
|
||||
} else {
|
||||
// copying
|
||||
assert(dst);
|
||||
memcpy(dst, start_sequence, sizeof(start_sequence));
|
||||
dst+= sizeof(start_sequence);
|
||||
memcpy(dst, src, nal_size);
|
||||
#ifdef DEBUG
|
||||
data->packet_types_received[*src & 0x1f]++;
|
||||
#endif
|
||||
dst+= nal_size;
|
||||
}
|
||||
} else {
|
||||
av_log(ctx, AV_LOG_ERROR,
|
||||
"nal size exceeds length: %d %d\n", nal_size, src_len);
|
||||
}
|
||||
|
||||
// eat what we handled...
|
||||
src += nal_size;
|
||||
src_len -= nal_size;
|
||||
|
||||
if (src_len < 0)
|
||||
av_log(ctx, AV_LOG_ERROR,
|
||||
"Consumed more bytes than we got! (%d)\n", src_len);
|
||||
} while (src_len > 2); // because there could be rtp padding..
|
||||
|
||||
if(pass==0) {
|
||||
// now we know the total size of the packet (with the start sequences added)
|
||||
av_new_packet(pkt, total_length);
|
||||
dst= pkt->data;
|
||||
} else {
|
||||
assert(dst-pkt->data==total_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 25: // STAP-B
|
||||
case 26: // MTAP-16
|
||||
case 27: // MTAP-24
|
||||
case 29: // FU-B
|
||||
av_log(ctx, AV_LOG_ERROR,
|
||||
"Unhandled type (%d) (See RFC for implementation details\n",
|
||||
type);
|
||||
result= -1;
|
||||
break;
|
||||
|
||||
case 28: // FU-A (fragmented nal)
|
||||
buf++;
|
||||
len--; // skip the fu_indicator
|
||||
{
|
||||
// these are the same as above, we just redo them here for clarity...
|
||||
uint8_t fu_indicator = nal;
|
||||
uint8_t fu_header = *buf; // read the fu_header.
|
||||
uint8_t start_bit = fu_header >> 7;
|
||||
// uint8_t end_bit = (fu_header & 0x40) >> 6;
|
||||
uint8_t nal_type = (fu_header & 0x1f);
|
||||
uint8_t reconstructed_nal;
|
||||
|
||||
// reconstruct this packet's true nal; only the data follows..
|
||||
reconstructed_nal = fu_indicator & (0xe0); // the original nal forbidden bit and NRI are stored in this packet's nal;
|
||||
reconstructed_nal |= nal_type;
|
||||
|
||||
// skip the fu_header...
|
||||
buf++;
|
||||
len--;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (start_bit)
|
||||
data->packet_types_received[nal_type]++;
|
||||
#endif
|
||||
if(start_bit) {
|
||||
// copy in the start sequence, and the reconstructed nal....
|
||||
av_new_packet(pkt, sizeof(start_sequence)+sizeof(nal)+len);
|
||||
memcpy(pkt->data, start_sequence, sizeof(start_sequence));
|
||||
pkt->data[sizeof(start_sequence)]= reconstructed_nal;
|
||||
memcpy(pkt->data+sizeof(start_sequence)+sizeof(nal), buf, len);
|
||||
} else {
|
||||
av_new_packet(pkt, len);
|
||||
memcpy(pkt->data, buf, len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 30: // undefined
|
||||
case 31: // undefined
|
||||
default:
|
||||
av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)", type);
|
||||
result= -1;
|
||||
break;
|
||||
}
|
||||
|
||||
pkt->stream_index = st->index;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ---------------- public code */
|
||||
static PayloadContext *h264_new_context(void)
|
||||
{
|
||||
PayloadContext *data =
|
||||
av_mallocz(sizeof(PayloadContext) +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
|
||||
if (data) {
|
||||
data->cookie = MAGIC_COOKIE;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void h264_free_context(PayloadContext *data)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
int ii;
|
||||
|
||||
for (ii = 0; ii < 32; ii++) {
|
||||
if (data->packet_types_received[ii])
|
||||
av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n",
|
||||
data->packet_types_received[ii], ii);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(data);
|
||||
assert(data->cookie == MAGIC_COOKIE);
|
||||
|
||||
// avoid stale pointers (assert)
|
||||
data->cookie = DEAD_COOKIE;
|
||||
|
||||
// and clear out this...
|
||||
av_free(data);
|
||||
}
|
||||
|
||||
static int parse_h264_sdp_line(AVFormatContext *s, int st_index,
|
||||
PayloadContext *h264_data, const char *line)
|
||||
{
|
||||
AVStream *stream = s->streams[st_index];
|
||||
AVCodecContext *codec = stream->codec;
|
||||
const char *p = line;
|
||||
|
||||
assert(h264_data->cookie == MAGIC_COOKIE);
|
||||
|
||||
if (av_strstart(p, "framesize:", &p)) {
|
||||
char buf1[50];
|
||||
char *dst = buf1;
|
||||
|
||||
// remove the protocol identifier..
|
||||
while (*p && *p == ' ') p++; // strip spaces.
|
||||
while (*p && *p != ' ') p++; // eat protocol identifier
|
||||
while (*p && *p == ' ') p++; // strip trailing spaces.
|
||||
while (*p && *p != '-' && (buf1 - dst) < sizeof(buf1) - 1) {
|
||||
*dst++ = *p++;
|
||||
}
|
||||
*dst = '\0';
|
||||
|
||||
// a='framesize:96 320-240'
|
||||
// set our parameters..
|
||||
codec->width = atoi(buf1);
|
||||
codec->height = atoi(p + 1); // skip the -
|
||||
codec->pix_fmt = PIX_FMT_YUV420P;
|
||||
} else if (av_strstart(p, "fmtp:", &p)) {
|
||||
char attr[256];
|
||||
char value[4096];
|
||||
|
||||
// remove the protocol identifier..
|
||||
while (*p && *p == ' ') p++; // strip spaces.
|
||||
while (*p && *p != ' ') p++; // eat protocol identifier
|
||||
while (*p && *p == ' ') p++; // strip trailing spaces.
|
||||
|
||||
/* loop on each attribute */
|
||||
while (rtsp_next_attr_and_value
|
||||
(&p, attr, sizeof(attr), value, sizeof(value))) {
|
||||
/* grab the codec extra_data from the config parameter of the fmtp line */
|
||||
sdp_parse_fmtp_config_h264(stream, h264_data, attr, value);
|
||||
}
|
||||
} else if (av_strstart(p, "cliprect:", &p)) {
|
||||
// could use this if we wanted.
|
||||
}
|
||||
|
||||
av_set_pts_info(stream, 33, 1, 90000); // 33 should be right, because the pts is 64 bit? (done elsewhere; this is a one time thing)
|
||||
|
||||
return 0; // keep processing it the normal way...
|
||||
}
|
||||
|
||||
/**
|
||||
This is the structure for expanding on the dynamic rtp protocols (makes everything static. yay!)
|
||||
*/
|
||||
RTPDynamicProtocolHandler ff_h264_dynamic_handler = {
|
||||
.enc_name = "H264",
|
||||
.codec_type = CODEC_TYPE_VIDEO,
|
||||
.codec_id = CODEC_ID_H264,
|
||||
.parse_sdp_a_line = parse_h264_sdp_line,
|
||||
.open = h264_new_context,
|
||||
.close = h264_free_context,
|
||||
.parse_packet = h264_handle_packet
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* RTP H264 Protocol (RFC3984)
|
||||
* Copyright (c) 2006 Ryan Martell
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_RTP_H264_H
|
||||
#define AVFORMAT_RTP_H264_H
|
||||
|
||||
#include "rtpdec.h"
|
||||
|
||||
extern RTPDynamicProtocolHandler ff_h264_dynamic_handler;
|
||||
void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size);
|
||||
|
||||
#endif /* AVFORMAT_RTP_H264_H */
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* RTP packetization for MPEG video
|
||||
* Copyright (c) 2002 Fabrice Bellard
|
||||
* Copyright (c) 2007 Luca Abeni
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavcodec/mpegvideo.h"
|
||||
#include "avformat.h"
|
||||
#include "rtpenc.h"
|
||||
|
||||
/* NOTE: a single frame must be passed with sequence header if
|
||||
needed. XXX: use slices. */
|
||||
void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size)
|
||||
{
|
||||
RTPMuxContext *s = s1->priv_data;
|
||||
int len, h, max_packet_size;
|
||||
uint8_t *q;
|
||||
const uint8_t *end = buf1 + size;
|
||||
int begin_of_slice, end_of_slice, frame_type, temporal_reference;
|
||||
|
||||
max_packet_size = s->max_payload_size;
|
||||
begin_of_slice = 1;
|
||||
end_of_slice = 0;
|
||||
frame_type = 0;
|
||||
temporal_reference = 0;
|
||||
|
||||
while (size > 0) {
|
||||
int begin_of_sequence;
|
||||
|
||||
begin_of_sequence = 0;
|
||||
len = max_packet_size - 4;
|
||||
|
||||
if (len >= size) {
|
||||
len = size;
|
||||
end_of_slice = 1;
|
||||
} else {
|
||||
const uint8_t *r, *r1;
|
||||
int start_code;
|
||||
|
||||
r1 = buf1;
|
||||
while (1) {
|
||||
start_code = -1;
|
||||
r = ff_find_start_code(r1, end, &start_code);
|
||||
if((start_code & 0xFFFFFF00) == 0x100) {
|
||||
/* New start code found */
|
||||
if (start_code == 0x100) {
|
||||
frame_type = (r[1] & 0x38) >> 3;
|
||||
temporal_reference = (int)r[0] << 2 | r[1] >> 6;
|
||||
}
|
||||
if (start_code == 0x1B8) {
|
||||
begin_of_sequence = 1;
|
||||
}
|
||||
|
||||
if (r - buf1 - 4 <= len) {
|
||||
/* The current slice fits in the packet */
|
||||
if (begin_of_slice == 0) {
|
||||
/* no slice at the beginning of the packet... */
|
||||
end_of_slice = 1;
|
||||
len = r - buf1 - 4;
|
||||
break;
|
||||
}
|
||||
r1 = r;
|
||||
} else {
|
||||
if ((r1 - buf1 > 4) && (r - r1 < max_packet_size)) {
|
||||
len = r1 - buf1 - 4;
|
||||
end_of_slice = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h = 0;
|
||||
h |= temporal_reference << 16;
|
||||
h |= begin_of_sequence << 13;
|
||||
h |= begin_of_slice << 12;
|
||||
h |= end_of_slice << 11;
|
||||
h |= frame_type << 8;
|
||||
|
||||
q = s->buf;
|
||||
*q++ = h >> 24;
|
||||
*q++ = h >> 16;
|
||||
*q++ = h >> 8;
|
||||
*q++ = h;
|
||||
|
||||
memcpy(q, buf1, len);
|
||||
q += len;
|
||||
|
||||
/* 90kHz time stamp */
|
||||
s->timestamp = s->cur_timestamp;
|
||||
ff_rtp_send_data(s1, s->buf, q - s->buf, (len == size));
|
||||
|
||||
buf1 += len;
|
||||
size -= len;
|
||||
begin_of_slice = end_of_slice;
|
||||
end_of_slice = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,218 +0,0 @@
|
||||
/*
|
||||
* RTP Vorbis Protocol (RFC5215)
|
||||
* Copyright (c) 2009 Colin McQuillan
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file libavformat/rtp_vorbis.c
|
||||
* @brief Vorbis / RTP Code (RFC 5215)
|
||||
* @author Colin McQuillan <m.niloc@gmail.com>
|
||||
*/
|
||||
|
||||
#include "libavutil/base64.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavcodec/bytestream.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "rtpdec.h"
|
||||
#include "rtp_vorbis.h"
|
||||
|
||||
/**
|
||||
* RTP/Vorbis specific private data.
|
||||
*/
|
||||
struct PayloadContext {
|
||||
unsigned ident; ///< 24-bit stream configuration identifier
|
||||
};
|
||||
|
||||
/**
|
||||
* Length encoding described in RFC5215 section 3.1.1.
|
||||
*/
|
||||
static int get_base128(const uint8_t ** buf, const uint8_t * buf_end)
|
||||
{
|
||||
int n = 0;
|
||||
for (; *buf < buf_end; ++*buf) {
|
||||
n <<= 7;
|
||||
n += **buf & 0x7f;
|
||||
if (!(**buf & 0x80)) {
|
||||
++*buf;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Out-of-band headers, described in RFC 5251 section 3.2.1
|
||||
*/
|
||||
static unsigned int
|
||||
parse_packed_headers(const uint8_t * packed_headers,
|
||||
const uint8_t * packed_headers_end,
|
||||
AVCodecContext * codec, PayloadContext * vorbis_data)
|
||||
{
|
||||
unsigned num_packed, num_headers, length, length1, length2;
|
||||
uint8_t *ptr;
|
||||
|
||||
num_packed = bytestream_get_be32(&packed_headers);
|
||||
vorbis_data->ident = bytestream_get_be24(&packed_headers);
|
||||
length = bytestream_get_be16(&packed_headers);
|
||||
num_headers = get_base128(&packed_headers, packed_headers_end);
|
||||
length1 = get_base128(&packed_headers, packed_headers_end);
|
||||
length2 = get_base128(&packed_headers, packed_headers_end);
|
||||
|
||||
if (num_packed != 1 || num_headers > 3) {
|
||||
av_log(codec, AV_LOG_ERROR,
|
||||
"Unimplemented number of headers: %d packed headers, %d headers\n",
|
||||
num_packed, num_headers);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (packed_headers_end - packed_headers != length ||
|
||||
length1 > length || length2 > length - length1) {
|
||||
av_log(codec, AV_LOG_ERROR,
|
||||
"Bad packed header lengths (%d,%d,%d,%d)\n", length1,
|
||||
length2, packed_headers_end - packed_headers, length);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
ptr = codec->extradata = av_mallocz(length + length / 255 + 64);
|
||||
if (!ptr) {
|
||||
av_log(codec, AV_LOG_ERROR, "Out of memory");
|
||||
return AVERROR_NOMEM;
|
||||
}
|
||||
*ptr++ = 2;
|
||||
ptr += av_xiphlacing(ptr, length1);
|
||||
ptr += av_xiphlacing(ptr, length2);
|
||||
memcpy(ptr, packed_headers, length);
|
||||
ptr += length;
|
||||
codec->extradata_size = ptr - codec->extradata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ff_vorbis_parse_fmtp_config(AVCodecContext * codec,
|
||||
void *vorbis_data, char *attr, char *value)
|
||||
{
|
||||
int result = 0;
|
||||
assert(codec->codec_id == CODEC_ID_VORBIS);
|
||||
assert(vorbis_data);
|
||||
|
||||
// The configuration value is a base64 encoded packed header
|
||||
if (!strcmp(attr, "configuration")) {
|
||||
uint8_t *decoded_packet = NULL;
|
||||
int packet_size;
|
||||
size_t decoded_alloc = strlen(value) / 4 * 3 + 4;
|
||||
|
||||
if (decoded_alloc <= INT_MAX) {
|
||||
decoded_packet = av_malloc(decoded_alloc);
|
||||
if (decoded_packet) {
|
||||
packet_size =
|
||||
av_base64_decode(decoded_packet, value, decoded_alloc);
|
||||
|
||||
result = parse_packed_headers
|
||||
(decoded_packet, decoded_packet + packet_size, codec,
|
||||
vorbis_data);
|
||||
} else {
|
||||
av_log(codec, AV_LOG_ERROR,
|
||||
"Out of memory while decoding SDP configuration.\n");
|
||||
result = AVERROR_NOMEM;
|
||||
}
|
||||
} else {
|
||||
av_log(codec, AV_LOG_ERROR, "Packet too large\n");
|
||||
result = AVERROR_INVALIDDATA;
|
||||
}
|
||||
av_free(decoded_packet);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static PayloadContext *vorbis_new_context(void)
|
||||
{
|
||||
return av_mallocz(sizeof(PayloadContext));
|
||||
}
|
||||
|
||||
static void vorbis_free_context(PayloadContext * data)
|
||||
{
|
||||
av_free(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle payload as described in RFC 5215 section 2.2
|
||||
*/
|
||||
static int
|
||||
vorbis_handle_packet(AVFormatContext * ctx,
|
||||
PayloadContext * data,
|
||||
AVStream * st,
|
||||
AVPacket * pkt,
|
||||
uint32_t * timestamp,
|
||||
const uint8_t * buf, int len, int flags)
|
||||
{
|
||||
int ident, fragmented, vdt, num_pkts, pkt_len;
|
||||
|
||||
if (len < 6) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
ident = AV_RB24(buf);
|
||||
fragmented = buf[3] >> 6;
|
||||
vdt = (buf[3] >> 4) & 3;
|
||||
num_pkts = buf[3] & 7;
|
||||
pkt_len = AV_RB16(buf + 4);
|
||||
|
||||
if (pkt_len > len - 6) {
|
||||
av_log(ctx, AV_LOG_ERROR,
|
||||
"Invalid packet length %d in %d byte packet\n", pkt_len,
|
||||
len);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (ident != data->ident) {
|
||||
av_log(ctx, AV_LOG_ERROR,
|
||||
"Unimplemented Vorbis SDP configuration change detected\n");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (fragmented != 0 || vdt != 0 || num_pkts != 1) {
|
||||
av_log(ctx, AV_LOG_ERROR,
|
||||
"Unimplemented RTP Vorbis packet settings (%d,%d,%d)\n",
|
||||
fragmented, vdt, num_pkts);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (av_new_packet(pkt, pkt_len)) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
|
||||
return AVERROR_NOMEM;
|
||||
}
|
||||
|
||||
memcpy(pkt->data, buf + 6, pkt_len);
|
||||
pkt->stream_index = st->index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = {
|
||||
.enc_name = "vorbis",
|
||||
.codec_type = CODEC_TYPE_AUDIO,
|
||||
.codec_id = CODEC_ID_VORBIS,
|
||||
.parse_sdp_a_line = NULL,
|
||||
.open = vorbis_new_context,
|
||||
.close = vorbis_free_context,
|
||||
.parse_packet = vorbis_handle_packet
|
||||
};
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* RTP Vorbis Protocol (RFC 5215)
|
||||
* Copyright (c) 2009 Colin McQuillan
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_RTP_VORBIS_H
|
||||
#define AVFORMAT_RTP_VORBIS_H
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "rtpdec.h"
|
||||
|
||||
/**
|
||||
* Handle a Vorbis-specific FMTP parameter
|
||||
*
|
||||
* @param codec The context of the codec
|
||||
* @param ctx Private Vorbis RTP context
|
||||
* @param attr Format-specific parameter name
|
||||
* @param value Format-specific paremeter value
|
||||
*/
|
||||
int
|
||||
ff_vorbis_parse_fmtp_config(AVCodecContext * codec,
|
||||
void *ctx, char *attr, char *value);
|
||||
|
||||
/**
|
||||
* Vorbis RTP callbacks.
|
||||
*/
|
||||
extern RTPDynamicProtocolHandler ff_vorbis_dynamic_handler;
|
||||
|
||||
#endif /* AVFORMAT_RTP_VORBIS_H */
|
@ -4,8 +4,8 @@ SubDir HAIKU_TOP src add-ons media plugins ffmpeg libavutil ;
|
||||
TARGET_WARNING_CCFLAGS = [ FFilter $(TARGET_WARNING_CCFLAGS)
|
||||
: -Wall -Wmissing-prototypes -Wsign-compare -Wpointer-arith ] ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) .. ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) ../libavcodec ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) libavcodec ] ;
|
||||
|
||||
# filter warnings we don't want here
|
||||
TARGET_WARNING_CCFLAGS = [ FFilter $(TARGET_WARNING_CCFLAGS)
|
||||
|
72
src/add-ons/media/plugins/ffmpeg/libavutil/arm/bswap.h
Normal file
72
src/add-ons/media/plugins/ffmpeg/libavutil/arm/bswap.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_ARM_BSWAP_H
|
||||
#define AVUTIL_ARM_BSWAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "libavutil/attributes.h"
|
||||
|
||||
#ifdef __ARMCC_VERSION
|
||||
|
||||
#if HAVE_ARMV6
|
||||
#define bswap_16 bswap_16
|
||||
static av_always_inline av_const unsigned bswap_16(unsigned x)
|
||||
{
|
||||
__asm { rev16 x, x }
|
||||
return x;
|
||||
}
|
||||
|
||||
#define bswap_32 bswap_32
|
||||
static av_always_inline av_const uint32_t bswap_32(uint32_t x)
|
||||
{
|
||||
return __rev(x);
|
||||
}
|
||||
#endif /* HAVE_ARMV6 */
|
||||
|
||||
#elif HAVE_INLINE_ASM
|
||||
|
||||
#if HAVE_ARMV6
|
||||
#define bswap_16 bswap_16
|
||||
static av_always_inline av_const unsigned bswap_16(unsigned x)
|
||||
{
|
||||
__asm__("rev16 %0, %0" : "+r"(x));
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define bswap_32 bswap_32
|
||||
static av_always_inline av_const uint32_t bswap_32(uint32_t x)
|
||||
{
|
||||
#if HAVE_ARMV6
|
||||
__asm__("rev %0, %0" : "+r"(x));
|
||||
#else
|
||||
uint32_t t;
|
||||
__asm__ ("eor %1, %0, %0, ror #16 \n\t"
|
||||
"bic %1, %1, #0xFF0000 \n\t"
|
||||
"mov %0, %0, ror #8 \n\t"
|
||||
"eor %0, %0, %1, lsr #8 \n\t"
|
||||
: "+r"(x), "=&r"(t));
|
||||
#endif /* HAVE_ARMV6 */
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif /* __ARMCC_VERSION */
|
||||
|
||||
#endif /* AVUTIL_ARM_BSWAP_H */
|
54
src/add-ons/media/plugins/ffmpeg/libavutil/arm/intmath.h
Normal file
54
src/add-ons/media/plugins/ffmpeg/libavutil/arm/intmath.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_ARM_INTMATH_H
|
||||
#define AVUTIL_ARM_INTMATH_H
|
||||
|
||||
#include "config.h"
|
||||
#include "libavutil/attributes.h"
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
|
||||
#if HAVE_ARMV6
|
||||
static inline av_const int FASTDIV(int a, int b)
|
||||
{
|
||||
int r, t;
|
||||
__asm__ volatile("cmp %3, #2 \n\t"
|
||||
"ldr %1, [%4, %3, lsl #2] \n\t"
|
||||
"lsrle %0, %2, #1 \n\t"
|
||||
"smmulgt %0, %1, %2 \n\t"
|
||||
: "=&r"(r), "=&r"(t) : "r"(a), "r"(b), "r"(ff_inverse));
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
static inline av_const int FASTDIV(int a, int b)
|
||||
{
|
||||
int r, t;
|
||||
__asm__ volatile("umull %1, %0, %2, %3"
|
||||
: "=&r"(r), "=&r"(t) : "r"(a), "r"(ff_inverse[b]));
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define FASTDIV FASTDIV
|
||||
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
|
||||
#endif /* AVUTIL_ARM_INTMATH_H */
|
@ -151,7 +151,7 @@ static inline av_const int16_t av_clip_int16(int a)
|
||||
*/
|
||||
static inline av_const int32_t av_clipl_int32(int64_t a)
|
||||
{
|
||||
if ((a+0x80000000u) & ~(0xFFFFFFFFULL)) return (a>>63) ^ 0x7FFFFFFF;
|
||||
if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (a>>63) ^ 0x7FFFFFFF;
|
||||
else return a;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user