Commit 4453f6b8 authored by Michael Niedermayer's avatar Michael Niedermayer

Merge remote-tracking branch 'qatar/master'

* qatar/master:
  flv: add support for G.711
  doc: git: Add checklist with test steps to perform before pushing
  flvenc: K&R formatting cosmetics
  movenc: Add channel layouts for PCM.

Conflicts:
	libavformat/flvenc.c
	tests/ref/fate/acodec-pcm-s16be
	tests/ref/fate/acodec-pcm-s24be
	tests/ref/fate/acodec-pcm-s32be
	tests/ref/fate/acodec-pcm-s8
Merged-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parents 7877b50d b92c7ee6
...@@ -346,6 +346,54 @@ git checkout -b svn_23456 $SHA1 ...@@ -346,6 +346,54 @@ git checkout -b svn_23456 $SHA1
where @var{$SHA1} is the commit hash from the @command{git log} output. where @var{$SHA1} is the commit hash from the @command{git log} output.
@chapter pre-push checklist
Once you have a set of commits that you feel are ready for pushing,
work through the following checklist to doublecheck everything is in
proper order. This list tries to be exhaustive. In case you are just
pushing a typo in a comment, some of the steps may be unnecessary.
Apply your common sense, but if in doubt, err on the side of caution.
First make sure your Git repository is on a branch that is a direct
descendant of the FFmpeg master branch, which is the only one from which
pushing to FFmpeg is possible. Then run the following command:
@itemize
@item @command{git log --patch --stat origin/master..}
to make sure that only the commits you want to push are pending, that
the log messages of the commits are correct and descriptive and contain
no cruft from @command{git am} and to doublecheck that the commits you
want to push really only contain the changes they are supposed to contain.
@item @command{git status}
to ensure no local changes still need to be committed and that no local
changes may have thrown off the results of your testing.
@end itemize
Next let the code pass through a full run of our testsuite. Before you do,
the command @command{make fate-rsync} will update the test samples. Changes
to the samples set are not very common and commits depending on samples
changes are delayed for at least 24 hours to allow the new samples to
propagate, so updating it once per day is sufficient. Now execute
@itemize
@item @command{make distclean}
@item @command{/path/to/ffmpeg/configure}
@item @command{make check}
@end itemize
While the test suite covers a wide range of possible problems, it is not
a panacea. Do not hesitate to perform any other tests necessary to convince
yourself that the changes you are about to push actually work as expected.
Also note that every single commit should pass the test suite, not just
the result of a series of patches. So if you have a series of related
commits, run the test suite on every single commit.
@chapter Server Issues @chapter Server Issues
Contact the project admins @email{root@@ffmpeg.org} if you have technical Contact the project admins @email{root@@ffmpeg.org} if you have technical
......
...@@ -94,6 +94,8 @@ enum { ...@@ -94,6 +94,8 @@ enum {
FLV_CODECID_NELLYMOSER_16KHZ_MONO = 4 << FLV_AUDIO_CODECID_OFFSET, FLV_CODECID_NELLYMOSER_16KHZ_MONO = 4 << FLV_AUDIO_CODECID_OFFSET,
FLV_CODECID_NELLYMOSER_8KHZ_MONO = 5 << FLV_AUDIO_CODECID_OFFSET, FLV_CODECID_NELLYMOSER_8KHZ_MONO = 5 << FLV_AUDIO_CODECID_OFFSET,
FLV_CODECID_NELLYMOSER = 6 << FLV_AUDIO_CODECID_OFFSET, FLV_CODECID_NELLYMOSER = 6 << FLV_AUDIO_CODECID_OFFSET,
FLV_CODECID_PCM_ALAW = 7 << FLV_AUDIO_CODECID_OFFSET,
FLV_CODECID_PCM_MULAW = 8 << FLV_AUDIO_CODECID_OFFSET,
FLV_CODECID_AAC = 10<< FLV_AUDIO_CODECID_OFFSET, FLV_CODECID_AAC = 10<< FLV_AUDIO_CODECID_OFFSET,
FLV_CODECID_SPEEX = 11<< FLV_AUDIO_CODECID_OFFSET, FLV_CODECID_SPEEX = 11<< FLV_AUDIO_CODECID_OFFSET,
}; };
......
...@@ -108,6 +108,14 @@ static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, AVCodecCo ...@@ -108,6 +108,14 @@ static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, AVCodecCo
case FLV_CODECID_NELLYMOSER: case FLV_CODECID_NELLYMOSER:
acodec->codec_id = CODEC_ID_NELLYMOSER; acodec->codec_id = CODEC_ID_NELLYMOSER;
break; break;
case FLV_CODECID_PCM_MULAW:
acodec->sample_rate = 8000;
acodec->codec_id = CODEC_ID_PCM_MULAW;
break;
case FLV_CODECID_PCM_ALAW:
acodec->sample_rate = 8000;
acodec->codec_id = CODEC_ID_PCM_ALAW;
break;
default: default:
av_log(s, AV_LOG_INFO, "Unsupported audio codec (%x)\n", flv_codecid >> FLV_AUDIO_CODECID_OFFSET); av_log(s, AV_LOG_INFO, "Unsupported audio codec (%x)\n", flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET; acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET;
......
...@@ -20,39 +20,41 @@ ...@@ -20,39 +20,41 @@
*/ */
#include "libavutil/intreadwrite.h" #include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/intfloat.h" #include "libavutil/intfloat.h"
#include "libavutil/avassert.h"
#include "avc.h"
#include "avformat.h" #include "avformat.h"
#include "flv.h" #include "flv.h"
#include "internal.h" #include "internal.h"
#include "avc.h"
#include "metadata.h" #include "metadata.h"
#include "libavutil/dict.h"
#include "libavutil/avassert.h"
static const AVCodecTag flv_video_codec_ids[] = { static const AVCodecTag flv_video_codec_ids[] = {
{CODEC_ID_FLV1, FLV_CODECID_H263 }, { CODEC_ID_FLV1, FLV_CODECID_H263 },
{CODEC_ID_H263, FLV_CODECID_REALH263}, { CODEC_ID_H263, FLV_CODECID_REALH263 },
{CODEC_ID_MPEG4, FLV_CODECID_MPEG4 }, { CODEC_ID_MPEG4, FLV_CODECID_MPEG4 },
{CODEC_ID_FLASHSV, FLV_CODECID_SCREEN}, { CODEC_ID_FLASHSV, FLV_CODECID_SCREEN },
{CODEC_ID_FLASHSV2, FLV_CODECID_SCREEN2}, { CODEC_ID_FLASHSV2, FLV_CODECID_SCREEN2 },
{CODEC_ID_VP6F, FLV_CODECID_VP6 }, { CODEC_ID_VP6F, FLV_CODECID_VP6 },
{CODEC_ID_VP6, FLV_CODECID_VP6 }, { CODEC_ID_VP6, FLV_CODECID_VP6 },
{CODEC_ID_VP6A, FLV_CODECID_VP6A }, { CODEC_ID_VP6A, FLV_CODECID_VP6A },
{CODEC_ID_H264, FLV_CODECID_H264 }, { CODEC_ID_H264, FLV_CODECID_H264 },
{CODEC_ID_NONE, 0} { CODEC_ID_NONE, 0 }
}; };
static const AVCodecTag flv_audio_codec_ids[] = { static const AVCodecTag flv_audio_codec_ids[] = {
{CODEC_ID_MP3, FLV_CODECID_MP3 >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_MP3, FLV_CODECID_MP3 >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_PCM_U8, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_PCM_U8, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_PCM_S16BE, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_PCM_S16BE, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_PCM_S16LE, FLV_CODECID_PCM_LE >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_PCM_S16LE, FLV_CODECID_PCM_LE >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_ADPCM_SWF, FLV_CODECID_ADPCM >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_ADPCM_SWF, FLV_CODECID_ADPCM >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_AAC, FLV_CODECID_AAC >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_AAC, FLV_CODECID_AAC >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_NELLYMOSER, FLV_CODECID_NELLYMOSER >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_NELLYMOSER, FLV_CODECID_NELLYMOSER >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_SPEEX, FLV_CODECID_SPEEX >> FLV_AUDIO_CODECID_OFFSET}, { CODEC_ID_PCM_MULAW, FLV_CODECID_PCM_MULAW >> FLV_AUDIO_CODECID_OFFSET },
{CODEC_ID_NONE, 0} { CODEC_ID_PCM_ALAW, FLV_CODECID_PCM_ALAW >> FLV_AUDIO_CODECID_OFFSET },
{ CODEC_ID_SPEEX, FLV_CODECID_SPEEX >> FLV_AUDIO_CODECID_OFFSET },
{ CODEC_ID_NONE, 0 }
}; };
typedef struct FLVContext { typedef struct FLVContext {
...@@ -69,13 +71,16 @@ typedef struct FLVStreamContext { ...@@ -69,13 +71,16 @@ typedef struct FLVStreamContext {
static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc) static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
{ {
int flags = (enc->bits_per_coded_sample == 16) ? FLV_SAMPLESSIZE_16BIT : FLV_SAMPLESSIZE_8BIT; int flags = (enc->bits_per_coded_sample == 16) ? FLV_SAMPLESSIZE_16BIT
: FLV_SAMPLESSIZE_8BIT;
if (enc->codec_id == CODEC_ID_AAC) // specs force these parameters if (enc->codec_id == CODEC_ID_AAC) // specs force these parameters
return FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ | FLV_SAMPLESSIZE_16BIT | FLV_STEREO; return FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ |
FLV_SAMPLESSIZE_16BIT | FLV_STEREO;
else if (enc->codec_id == CODEC_ID_SPEEX) { else if (enc->codec_id == CODEC_ID_SPEEX) {
if (enc->sample_rate != 16000) { if (enc->sample_rate != 16000) {
av_log(s, AV_LOG_ERROR, "flv only supports wideband (16kHz) Speex audio\n"); av_log(s, AV_LOG_ERROR,
"flv only supports wideband (16kHz) Speex audio\n");
return -1; return -1;
} }
if (enc->channels != 1) { if (enc->channels != 1) {
...@@ -94,24 +99,25 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc) ...@@ -94,24 +99,25 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
case 11025: case 11025:
flags |= FLV_SAMPLERATE_11025HZ; flags |= FLV_SAMPLERATE_11025HZ;
break; break;
case 16000: //nellymoser only case 16000: // nellymoser only
case 8000: //nellymoser only case 8000: // nellymoser only
case 5512: //not mp3 case 5512: // not MP3
if(enc->codec_id != CODEC_ID_MP3){ if (enc->codec_id != CODEC_ID_MP3) {
flags |= FLV_SAMPLERATE_SPECIAL; flags |= FLV_SAMPLERATE_SPECIAL;
break; break;
} }
default: default:
av_log(s, AV_LOG_ERROR, "flv does not support that sample rate, choose from (44100, 22050, 11025).\n"); av_log(s, AV_LOG_ERROR,
"flv does not support that sample rate, "
"choose from (44100, 22050, 11025).\n");
return -1; return -1;
} }
} }
if (enc->channels > 1) { if (enc->channels > 1)
flags |= FLV_STEREO; flags |= FLV_STEREO;
}
switch(enc->codec_id){ switch (enc->codec_id) {
case CODEC_ID_MP3: case CODEC_ID_MP3:
flags |= FLV_CODECID_MP3 | FLV_SAMPLESSIZE_16BIT; flags |= FLV_CODECID_MP3 | FLV_SAMPLESSIZE_16BIT;
break; break;
...@@ -128,16 +134,21 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc) ...@@ -128,16 +134,21 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
flags |= FLV_CODECID_ADPCM | FLV_SAMPLESSIZE_16BIT; flags |= FLV_CODECID_ADPCM | FLV_SAMPLESSIZE_16BIT;
break; break;
case CODEC_ID_NELLYMOSER: case CODEC_ID_NELLYMOSER:
if (enc->sample_rate == 8000) { if (enc->sample_rate == 8000)
flags |= FLV_CODECID_NELLYMOSER_8KHZ_MONO | FLV_SAMPLESSIZE_16BIT; flags |= FLV_CODECID_NELLYMOSER_8KHZ_MONO | FLV_SAMPLESSIZE_16BIT;
} else if (enc->sample_rate == 16000) { else if (enc->sample_rate == 16000)
flags |= FLV_CODECID_NELLYMOSER_16KHZ_MONO | FLV_SAMPLESSIZE_16BIT; flags |= FLV_CODECID_NELLYMOSER_16KHZ_MONO | FLV_SAMPLESSIZE_16BIT;
} else { else
flags |= FLV_CODECID_NELLYMOSER | FLV_SAMPLESSIZE_16BIT; flags |= FLV_CODECID_NELLYMOSER | FLV_SAMPLESSIZE_16BIT;
} break;
case CODEC_ID_PCM_MULAW:
flags = FLV_CODECID_PCM_MULAW | FLV_SAMPLERATE_SPECIAL | FLV_SAMPLESSIZE_16BIT;
break;
case CODEC_ID_PCM_ALAW:
flags = FLV_CODECID_PCM_ALAW | FLV_SAMPLERATE_SPECIAL | FLV_SAMPLESSIZE_16BIT;
break; break;
case 0: case 0:
flags |= enc->codec_tag<<4; flags |= enc->codec_tag << 4;
break; break;
default: default:
av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n"); av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n");
...@@ -154,11 +165,12 @@ static void put_amf_string(AVIOContext *pb, const char *str) ...@@ -154,11 +165,12 @@ static void put_amf_string(AVIOContext *pb, const char *str)
avio_write(pb, str, len); avio_write(pb, str, len);
} }
static void put_avc_eos_tag(AVIOContext *pb, unsigned ts) { static void put_avc_eos_tag(AVIOContext *pb, unsigned ts)
{
avio_w8(pb, FLV_TAG_TYPE_VIDEO); avio_w8(pb, FLV_TAG_TYPE_VIDEO);
avio_wb24(pb, 5); /* Tag Data Size */ avio_wb24(pb, 5); /* Tag Data Size */
avio_wb24(pb, ts); /* lower 24 bits of timestamp in ms*/ avio_wb24(pb, ts); /* lower 24 bits of timestamp in ms */
avio_w8(pb, (ts >> 24) & 0x7F); /* MSB of ts in ms*/ avio_w8(pb, (ts >> 24) & 0x7F); /* MSB of ts in ms */
avio_wb24(pb, 0); /* StreamId = 0 */ avio_wb24(pb, 0); /* StreamId = 0 */
avio_w8(pb, 23); /* ub[4] FrameType = 1, ub[4] CodecId = 7 */ avio_w8(pb, 23); /* ub[4] FrameType = 1, ub[4] CodecId = 7 */
avio_w8(pb, 2); /* AVC end of sequence */ avio_w8(pb, 2); /* AVC end of sequence */
...@@ -172,7 +184,8 @@ static void put_amf_double(AVIOContext *pb, double d) ...@@ -172,7 +184,8 @@ static void put_amf_double(AVIOContext *pb, double d)
avio_wb64(pb, av_double2int(d)); avio_wb64(pb, av_double2int(d));
} }
static void put_amf_bool(AVIOContext *pb, int b) { static void put_amf_bool(AVIOContext *pb, int b)
{
avio_w8(pb, AMF_DATA_TYPE_BOOL); avio_w8(pb, AMF_DATA_TYPE_BOOL);
avio_w8(pb, !!b); avio_w8(pb, !!b);
} }
...@@ -187,18 +200,19 @@ static int flv_write_header(AVFormatContext *s) ...@@ -187,18 +200,19 @@ static int flv_write_header(AVFormatContext *s)
int64_t metadata_size_pos, data_size, metadata_count_pos; int64_t metadata_size_pos, data_size, metadata_count_pos;
AVDictionaryEntry *tag = NULL; AVDictionaryEntry *tag = NULL;
for(i=0; i<s->nb_streams; i++){ for (i = 0; i < s->nb_streams; i++) {
AVCodecContext *enc = s->streams[i]->codec; AVCodecContext *enc = s->streams[i]->codec;
FLVStreamContext *sc; FLVStreamContext *sc;
switch (enc->codec_type) { switch (enc->codec_type) {
case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_VIDEO:
if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { if (s->streams[i]->r_frame_rate.den &&
s->streams[i]->r_frame_rate.num) {
framerate = av_q2d(s->streams[i]->r_frame_rate); framerate = av_q2d(s->streams[i]->r_frame_rate);
} else { } else {
framerate = 1/av_q2d(s->streams[i]->codec->time_base); framerate = 1 / av_q2d(s->streams[i]->codec->time_base);
} }
video_enc = enc; video_enc = enc;
if(enc->codec_tag == 0) { if (enc->codec_tag == 0) {
av_log(s, AV_LOG_ERROR, "video codec not compatible with flv\n"); av_log(s, AV_LOG_ERROR, "video codec not compatible with flv\n");
return -1; return -1;
} }
...@@ -227,31 +241,31 @@ static int flv_write_header(AVFormatContext *s) ...@@ -227,31 +241,31 @@ static int flv_write_header(AVFormatContext *s)
s->streams[i]->priv_data = sc; s->streams[i]->priv_data = sc;
sc->last_ts = -1; sc->last_ts = -1;
} }
flv->delay = AV_NOPTS_VALUE; flv->delay = AV_NOPTS_VALUE;
avio_write(pb, "FLV", 3); avio_write(pb, "FLV", 3);
avio_w8(pb,1); avio_w8(pb, 1);
avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!audio_enc avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!audio_enc +
+ FLV_HEADER_FLAG_HASVIDEO * !!video_enc); FLV_HEADER_FLAG_HASVIDEO * !!video_enc);
avio_wb32(pb,9); avio_wb32(pb, 9);
avio_wb32(pb,0); avio_wb32(pb, 0);
for(i=0; i<s->nb_streams; i++){ for (i = 0; i < s->nb_streams; i++)
if(s->streams[i]->codec->codec_tag == 5){ if (s->streams[i]->codec->codec_tag == 5) {
avio_w8(pb,8); // message type avio_w8(pb, 8); // message type
avio_wb24(pb,0); // include flags avio_wb24(pb, 0); // include flags
avio_wb24(pb,0); // time stamp avio_wb24(pb, 0); // time stamp
avio_wb32(pb,0); // reserved avio_wb32(pb, 0); // reserved
avio_wb32(pb,11); // size avio_wb32(pb, 11); // size
flv->reserved=5; flv->reserved = 5;
}
} }
/* write meta_tag */ /* write meta_tag */
avio_w8(pb, 18); // tag type META avio_w8(pb, 18); // tag type META
metadata_size_pos= avio_tell(pb); metadata_size_pos = avio_tell(pb);
avio_wb24(pb, 0); // size of data part (sum of all parts below) avio_wb24(pb, 0); // size of data part (sum of all parts below)
avio_wb24(pb, 0); // time stamp avio_wb24(pb, 0); // timestamp
avio_wb32(pb, 0); // reserved avio_wb32(pb, 0); // reserved
/* now data of data_size size */ /* now data of data_size size */
...@@ -272,9 +286,11 @@ static int flv_write_header(AVFormatContext *s) ...@@ -272,9 +286,11 @@ static int flv_write_header(AVFormatContext *s)
put_amf_string(pb, "duration"); put_amf_string(pb, "duration");
flv->duration_offset= avio_tell(pb); flv->duration_offset= avio_tell(pb);
put_amf_double(pb, s->duration / AV_TIME_BASE); // fill in the guessed duration, it'll be corrected later if incorrect
if(video_enc){ // fill in the guessed duration, it'll be corrected later if incorrect
put_amf_double(pb, s->duration / AV_TIME_BASE);
if (video_enc) {
put_amf_string(pb, "width"); put_amf_string(pb, "width");
put_amf_double(pb, video_enc->width); put_amf_double(pb, video_enc->width);
...@@ -291,7 +307,7 @@ static int flv_write_header(AVFormatContext *s) ...@@ -291,7 +307,7 @@ static int flv_write_header(AVFormatContext *s)
put_amf_double(pb, video_enc->codec_tag); put_amf_double(pb, video_enc->codec_tag);
} }
if(audio_enc){ if (audio_enc) {
put_amf_string(pb, "audiodatarate"); put_amf_string(pb, "audiodatarate");
put_amf_double(pb, audio_enc->bit_rate / 1024.0); put_amf_double(pb, audio_enc->bit_rate / 1024.0);
...@@ -337,14 +353,14 @@ static int flv_write_header(AVFormatContext *s) ...@@ -337,14 +353,14 @@ static int flv_write_header(AVFormatContext *s)
} }
put_amf_string(pb, "filesize"); put_amf_string(pb, "filesize");
flv->filesize_offset= avio_tell(pb); flv->filesize_offset = avio_tell(pb);
put_amf_double(pb, 0); // delayed write put_amf_double(pb, 0); // delayed write
put_amf_string(pb, ""); put_amf_string(pb, "");
avio_w8(pb, AMF_END_OF_OBJECT); avio_w8(pb, AMF_END_OF_OBJECT);
/* write total size of tag */ /* write total size of tag */
data_size= avio_tell(pb) - metadata_size_pos - 10; data_size = avio_tell(pb) - metadata_size_pos - 10;
avio_seek(pb, metadata_count_pos, SEEK_SET); avio_seek(pb, metadata_count_pos, SEEK_SET);
avio_wb32(pb, metadata_count); avio_wb32(pb, metadata_count);
...@@ -399,10 +415,9 @@ static int flv_write_trailer(AVFormatContext *s) ...@@ -399,10 +415,9 @@ static int flv_write_trailer(AVFormatContext *s)
AVCodecContext *enc = s->streams[i]->codec; AVCodecContext *enc = s->streams[i]->codec;
FLVStreamContext *sc = s->streams[i]->priv_data; FLVStreamContext *sc = s->streams[i]->priv_data;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO && if (enc->codec_type == AVMEDIA_TYPE_VIDEO &&
(enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4)) { (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4))
put_avc_eos_tag(pb, sc->last_ts); put_avc_eos_tag(pb, sc->last_ts);
} }
}
file_size = avio_tell(pb); file_size = avio_tell(pb);
...@@ -423,27 +438,30 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -423,27 +438,30 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
FLVContext *flv = s->priv_data; FLVContext *flv = s->priv_data;
FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data; FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data;
unsigned ts; unsigned ts;
int size= pkt->size; int size = pkt->size;
uint8_t *data= NULL; uint8_t *data = NULL;
int flags, flags_size; int flags, flags_size;
// av_log(s, AV_LOG_DEBUG, "type:%d pts: %"PRId64" size:%d\n", enc->codec_type, timestamp, size); // av_log(s, AV_LOG_DEBUG, "type:%d pts: %"PRId64" size:%d\n",
// enc->codec_type, timestamp, size);
if(enc->codec_id == CODEC_ID_VP6 || enc->codec_id == CODEC_ID_VP6F || if (enc->codec_id == CODEC_ID_VP6 || enc->codec_id == CODEC_ID_VP6F ||
enc->codec_id == CODEC_ID_VP6A || enc->codec_id == CODEC_ID_AAC) enc->codec_id == CODEC_ID_VP6A || enc->codec_id == CODEC_ID_AAC)
flags_size= 2; flags_size = 2;
else if(enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) else if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4)
flags_size= 5; flags_size = 5;
else else
flags_size= 1; flags_size = 1;
switch (enc->codec_type) { switch (enc->codec_type) {
case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_VIDEO:
avio_w8(pb, FLV_TAG_TYPE_VIDEO); avio_w8(pb, FLV_TAG_TYPE_VIDEO);
flags = enc->codec_tag; flags = enc->codec_tag;
if(flags == 0) { if (flags == 0) {
av_log(s, AV_LOG_ERROR, "video codec %s not compatible with flv\n", avcodec_get_name(enc->codec_id)); av_log(s, AV_LOG_ERROR,
"video codec %s not compatible with flv\n",
avcodec_get_name(enc->codec_id));
return -1; return -1;
} }
...@@ -462,41 +480,42 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -462,41 +480,42 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
default: default:
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) { if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) {
/* check if extradata looks like mp4 formated */ /* check if extradata looks like mp4 formated */
if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) { if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1)
if (ff_avc_parse_nal_units_buf(pkt->data, &data, &size) < 0) if (ff_avc_parse_nal_units_buf(pkt->data, &data, &size) < 0)
return -1; return -1;
}
} else if (enc->codec_id == CODEC_ID_AAC && pkt->size > 2 && } else if (enc->codec_id == CODEC_ID_AAC && pkt->size > 2 &&
(AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
av_log(s, AV_LOG_ERROR, "malformated aac bitstream, use -absf aac_adtstoasc\n"); av_log(s, AV_LOG_ERROR, "malformated aac bitstream, use -absf aac_adtstoasc\n");
return -1; return -1;
} }
if (flv->delay == AV_NOPTS_VALUE) if (flv->delay == AV_NOPTS_VALUE)
flv->delay = -pkt->dts; flv->delay = -pkt->dts;
if (pkt->dts < -flv->delay) { if (pkt->dts < -flv->delay) {
av_log(s, AV_LOG_WARNING, "Packets are not in the proper order with " av_log(s, AV_LOG_WARNING,
"respect to DTS\n"); "Packets are not in the proper order with respect to DTS\n");
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
ts = pkt->dts + flv->delay; // add delay to force positive dts ts = pkt->dts + flv->delay; // add delay to force positive dts
/* check Speex packet duration */ /* check Speex packet duration */
if (enc->codec_id == CODEC_ID_SPEEX && ts - sc->last_ts > 160) { if (enc->codec_id == CODEC_ID_SPEEX && ts - sc->last_ts > 160)
av_log(s, AV_LOG_WARNING, "Warning: Speex stream has more than " av_log(s, AV_LOG_WARNING, "Warning: Speex stream has more than "
"8 frames per packet. Adobe Flash " "8 frames per packet. Adobe Flash "
"Player cannot handle this!\n"); "Player cannot handle this!\n");
}
if (sc->last_ts < ts) if (sc->last_ts < ts)
sc->last_ts = ts; sc->last_ts = ts;
avio_wb24(pb,size + flags_size); avio_wb24(pb, size + flags_size);
avio_wb24(pb,ts); avio_wb24(pb, ts);
avio_w8(pb,(ts >> 24) & 0x7F); // timestamps are 32bits _signed_ avio_w8(pb, (ts >> 24) & 0x7F); // timestamps are 32 bits _signed_
avio_wb24(pb,flv->reserved); avio_wb24(pb, flv->reserved);
if (enc->codec_type == AVMEDIA_TYPE_DATA) { if (enc->codec_type == AVMEDIA_TYPE_DATA) {
int data_size; int data_size;
...@@ -534,11 +553,12 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -534,11 +553,12 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_write(pb, data ? data : pkt->data, size); avio_write(pb, data ? data : pkt->data, size);
avio_wb32(pb,size+flags_size+11); // previous tag size avio_wb32(pb, size + flags_size + 11); // previous tag size
flv->duration = FFMAX(flv->duration, pkt->pts + flv->delay + pkt->duration); flv->duration = FFMAX(flv->duration,
pkt->pts + flv->delay + pkt->duration);
} }
avio_flush(pb);
avio_flush(pb);
av_free(data); av_free(data);
return pb->error; return pb->error;
...@@ -559,7 +579,7 @@ AVOutputFormat ff_flv_muxer = { ...@@ -559,7 +579,7 @@ AVOutputFormat ff_flv_muxer = {
.write_header = flv_write_header, .write_header = flv_write_header,
.write_packet = flv_write_packet, .write_packet = flv_write_packet,
.write_trailer = flv_write_trailer, .write_trailer = flv_write_trailer,
.codec_tag = (const AVCodecTag* const []){ .codec_tag = (const AVCodecTag* const []) {
flv_video_codec_ids, flv_audio_codec_ids, 0 flv_video_codec_ids, flv_audio_codec_ids, 0
}, },
.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
......
...@@ -414,6 +414,20 @@ static const enum MovChannelLayoutTag mov_ch_layouts_alac[] = { ...@@ -414,6 +414,20 @@ static const enum MovChannelLayoutTag mov_ch_layouts_alac[] = {
0, 0,
}; };
static const enum MovChannelLayoutTag mov_ch_layouts_wav[] = {
MOV_CH_LAYOUT_MONO,
MOV_CH_LAYOUT_STEREO,
MOV_CH_LAYOUT_MATRIXSTEREO,
MOV_CH_LAYOUT_MPEG_3_0_A,
MOV_CH_LAYOUT_QUADRAPHONIC,
MOV_CH_LAYOUT_MPEG_5_0_A,
MOV_CH_LAYOUT_MPEG_5_1_A,
MOV_CH_LAYOUT_MPEG_6_1_A,
MOV_CH_LAYOUT_MPEG_7_1_A,
MOV_CH_LAYOUT_MPEG_7_1_C,
MOV_CH_LAYOUT_SMPTE_DTV,
};
static const struct { static const struct {
enum CodecID codec_id; enum CodecID codec_id;
const enum MovChannelLayoutTag *layouts; const enum MovChannelLayoutTag *layouts;
...@@ -421,6 +435,18 @@ static const struct { ...@@ -421,6 +435,18 @@ static const struct {
{ CODEC_ID_AAC, mov_ch_layouts_aac }, { CODEC_ID_AAC, mov_ch_layouts_aac },
{ CODEC_ID_AC3, mov_ch_layouts_ac3 }, { CODEC_ID_AC3, mov_ch_layouts_ac3 },
{ CODEC_ID_ALAC, mov_ch_layouts_alac }, { CODEC_ID_ALAC, mov_ch_layouts_alac },
{ CODEC_ID_PCM_U8, mov_ch_layouts_wav },
{ CODEC_ID_PCM_S8, mov_ch_layouts_wav },
{ CODEC_ID_PCM_S16LE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_S16BE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_S24LE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_S24BE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_S32LE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_S32BE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_F32LE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_F32BE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_F64LE, mov_ch_layouts_wav },
{ CODEC_ID_PCM_F64BE, mov_ch_layouts_wav },
{ CODEC_ID_NONE, NULL }, { CODEC_ID_NONE, NULL },
}; };
......
8bffa66afe9e17366af11e77882518a0 *tests/data/fate/acodec-pcm-s16be.mov d00ca427a66be2e33ca8d63bcde41316 *tests/data/fate/acodec-pcm-s16be.mov
1059069 tests/data/fate/acodec-pcm-s16be.mov 1059069 tests/data/fate/acodec-pcm-s16be.mov
64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s16be.out.wav 64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s16be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
e3013cfce9b792acb9d572268012160d *tests/data/fate/acodec-pcm-s24be.mov 5d843e1f56796aae3185016f164b16b7 *tests/data/fate/acodec-pcm-s24be.mov
1588269 tests/data/fate/acodec-pcm-s24be.mov 1588269 tests/data/fate/acodec-pcm-s24be.mov
64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s24be.out.wav 64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s24be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
f3ef00480e89c5c791e87b8af1cc167c *tests/data/fate/acodec-pcm-s32be.mov b34c66c56df1b1e75688929cf20670b9 *tests/data/fate/acodec-pcm-s32be.mov
2117473 tests/data/fate/acodec-pcm-s32be.mov 2117473 tests/data/fate/acodec-pcm-s32be.mov
64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s32be.out.wav 64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s32be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
2c504a4e48c19ea1b0e1705893b771bf *tests/data/fate/acodec-pcm-s8.mov d931dc4fffa2d3398e0f31f97e7d6c3a *tests/data/fate/acodec-pcm-s8.mov
529853 tests/data/fate/acodec-pcm-s8.mov 529853 tests/data/fate/acodec-pcm-s8.mov
651d4eb8d98dfcdda96ae6c43d8f156b *tests/data/fate/acodec-pcm-s8.out.wav 651d4eb8d98dfcdda96ae6c43d8f156b *tests/data/fate/acodec-pcm-s8.out.wav
stddev: 147.89 PSNR: 52.93 MAXDIFF: 255 bytes: 1058400/ 1058400 stddev: 147.89 PSNR: 52.93 MAXDIFF: 255 bytes: 1058400/ 1058400
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment