分类: C/C++
2012-05-02 17:21:14
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
FLVContext *flv = (FLVContext*)s->priv_data;
FLVStreamContext *sc = (FLVStreamContext*)s->streams[pkt->stream_index]->priv_data;
unsigned ts;
int size= pkt->size;
uint8_t *data= NULL;
int flags, flags_size;
/********** Add KeyFrame Index ***********************************/
int64_t vbegin_offset = avio_tell(pb);
/************************************************************************/
// 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 ||
enc->codec_id == CODEC_ID_AAC)
flags_size= 2;
else if(enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4)
flags_size= 5;
else
flags_size= 1;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
avio_w8(pb, FLV_TAG_TYPE_VIDEO);
flags = enc->codec_tag;
if(flags == 0) {
av_log(enc, AV_LOG_ERROR, "video codec %s not compatible with flv\n", avcodec_get_name(enc->codec_id));
return -1;
}
flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER;
} else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
flags = get_audio_flags(enc);
assert(size);
avio_w8(pb, FLV_TAG_TYPE_AUDIO);
} else {
// In-band flv metadata ("scriptdata")
assert(enc->codec_type == AVMEDIA_TYPE_DATA);
avio_w8(pb, FLV_TAG_TYPE_META);
flags_size = 0;
flags = 0;
}
if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) {
/* check if extradata looks like mp4 formated */
if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) {
if (ff_avc_parse_nal_units_buf(pkt->data, &data, &size) < 0)
return -1;
}
} else if (enc->codec_id == CODEC_ID_AAC && pkt->size > 2 &&
(AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
av_log(s, AV_LOG_ERROR, "malformated aac bitstream, use -absf aac_adtstoasc\n");
return -1;
}
if (flv->delay == AV_NOPTS_VALUE)
flv->delay = -pkt->dts;
if (pkt->dts < -flv->delay) {
av_log(s, AV_LOG_WARNING, "Packets are not in the proper order with "
"respect to DTS\n");
return AVERROR(EINVAL);
}
ts = pkt->dts + flv->delay; // add delay to force positive dts
/* check Speex packet duration */
if (enc->codec_id == CODEC_ID_SPEEX && ts - sc->last_ts > 160) {
av_log(s, AV_LOG_WARNING, "Warning: Speex stream has more than "
"8 frames per packet. Adobe Flash "
"Player cannot handle this!\n");
}
if (sc->last_ts < ts)
sc->last_ts = ts;
avio_wb24(pb,size + flags_size);
avio_wb24(pb,ts);
avio_w8(pb,(ts >> 24) & 0x7F); // timestamps are 32bits _signed_
avio_wb24(pb,flv->reserved);
if(flags_size)
avio_w8(pb,flags);
if (enc->codec_id == CODEC_ID_VP6)
avio_w8(pb,0);
if (enc->codec_id == CODEC_ID_VP6F)
avio_w8(pb, enc->extradata_size ? enc->extradata[0] : 0);
else if (enc->codec_id == CODEC_ID_AAC)
avio_w8(pb,1); // AAC raw
else if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) {
avio_w8(pb,1); // AVC NALU
avio_wb24(pb,pkt->pts - pkt->dts);
}
avio_write(pb, data ? data : pkt->data, size);
avio_wb32(pb,size+flags_size+11); // previous tag size
flv->duration = FFMAX(flv->duration, pkt->pts + flv->delay + pkt->duration);
/********** Add KeyFrame Index ***********************************/
if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
{
flv->videosize += (avio_tell(pb) - vbegin_offset);
flv->lasttimestamp = flv->acurframeindex / flv->framerate;
if (pkt->flags & AV_PKT_FLAG_KEY)
{
flv->lastkeyframelocation = vbegin_offset;
flv->lastkeyframetimestamp = flv->acurframeindex / flv->framerate;
flv->filepositions.Add(flv->lastkeyframelocation);
flv->filetimes.Add(flv->lastkeyframetimestamp);
}
flv->acurframeindex++;
}
else if (enc->codec_type == AVMEDIA_TYPE_AUDIO)
{
flv->audiosize += (avio_tell(pb) - vbegin_offset);
}
/************************************************************************/
avio_flush(pb);
av_free(data);
return pb->error;
}
static AVCodecTag* ff_flv_tag[] = {(AVCodecTag*)flv_video_codec_ids, (AVCodecTag*)flv_audio_codec_ids, 0};
AVOutputFormat my_ff_flv_muxer = {
"flv",
"FLV format",
"video/x-flv",
"flv",
sizeof(FLVContext),
CODEC_ID_ADPCM_SWF,
CODEC_ID_FLV1,
flv_write_header,
flv_write_packet,
flv_write_trailer,
AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
NULL,
NULL,
ff_flv_tag,
};
};