static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { ByteIOContext *pb = &s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; int size= pkt->size; int flags; // av_log(s, AV_LOG_DEBUG, "type:%d pts: %"PRId64" size:%d\n", enc->codec_type, timestamp, size); if (enc->codec_type == CODEC_TYPE_VIDEO) { put_byte(pb, 9); flags = 2; // choose h263 flags |= pkt->flags & PKT_FLAG_KEY ? 0x10 : 0x20; // add keyframe indicator } else { assert(enc->codec_type == CODEC_TYPE_AUDIO); flags = get_audio_flags(enc); assert(size); put_byte(pb, 8); } put_be24(pb,size+1); // include flags put_be24(pb,pkt->pts); put_be32(pb,flv->reserved); put_byte(pb,flags); put_buffer(pb, pkt->data, size); put_be32(pb,size+1+11); // previous tag size flv->duration = pkt->pts + pkt->duration; put_flush_packet(pb); return 0; }
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { ByteIOContext *pb = s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; int size= pkt->size; int flags, flags_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) flags_size= 2; else flags_size= 1; if (enc->codec_type == CODEC_TYPE_VIDEO) { put_byte(pb, FLV_TAG_TYPE_VIDEO); flags = enc->codec_tag; if(flags == 0) { av_log(enc, AV_LOG_ERROR, "video codec %X not compatible with flv\n",enc->codec_id); return -1; } flags |= pkt->flags & PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; } else { assert(enc->codec_type == CODEC_TYPE_AUDIO); flags = get_audio_flags(enc); assert(size); put_byte(pb, FLV_TAG_TYPE_AUDIO); } put_be24(pb,size + flags_size); put_be24(pb,pkt->pts); put_byte(pb,pkt->pts >> 24); put_be24(pb,flv->reserved); put_byte(pb,flags); if (enc->codec_id == CODEC_ID_VP6) put_byte(pb,0); if (enc->codec_id == CODEC_ID_VP6F) put_byte(pb, enc->extradata_size ? enc->extradata[0] : 0); put_buffer(pb, pkt->data, size); put_be32(pb,size+flags_size+11); // previous tag size flv->duration = pkt->pts + pkt->duration; put_flush_packet(pb); return 0; }
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data; unsigned ts; int size= pkt->size; uint8_t *data= NULL; int flags, flags_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 || enc->codec_id == CODEC_ID_AAC) flags_size= 2; else if(enc->codec_id == CODEC_ID_H264) 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 %X not compatible with flv\n",enc->codec_id); return -1; } flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; } else { assert(enc->codec_type == AVMEDIA_TYPE_AUDIO); flags = get_audio_flags(enc); assert(size); avio_w8(pb, FLV_TAG_TYPE_AUDIO); } if (enc->codec_id == CODEC_ID_H264) { /* check if extradata looks like MP4 */ if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) { if (ff_avc_parse_nal_units_buf(pkt->data, &data, &size) < 0) 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); 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) { 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); avio_flush(pb); av_free(data); return pb->error; }
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data; unsigned ts; int size = pkt->size; uint8_t *data = NULL; int flags, flags_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 || enc->codec_id == CODEC_ID_VP6A || 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; switch (enc->codec_type) { case AVMEDIA_TYPE_VIDEO: avio_w8(pb, FLV_TAG_TYPE_VIDEO); flags = enc->codec_tag; if (flags == 0) { av_log(s, 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; break; case AVMEDIA_TYPE_AUDIO: flags = get_audio_flags(s, enc); av_assert0(size); avio_w8(pb, FLV_TAG_TYPE_AUDIO); break; case AVMEDIA_TYPE_DATA: avio_w8(pb, FLV_TAG_TYPE_META); break; default: return AVERROR(EINVAL); } 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 32 bits _signed_ avio_wb24(pb, flv->reserved); if (enc->codec_type == AVMEDIA_TYPE_DATA) { int data_size; int metadata_size_pos = avio_tell(pb); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onTextData"); avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); avio_wb32(pb, 2); put_amf_string(pb, "type"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "Text"); put_amf_string(pb, "text"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, pkt->data); put_amf_string(pb, ""); avio_w8(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size = avio_tell(pb) - metadata_size_pos; avio_seek(pb, metadata_size_pos - 10, SEEK_SET); avio_wb24(pb, data_size); avio_seek(pb, data_size + 10 - 3, SEEK_CUR); avio_wb32(pb, data_size + 11); } else { avio_w8(pb,flags); if (enc->codec_id == CODEC_ID_VP6) avio_w8(pb,0); if (enc->codec_id == CODEC_ID_VP6F || enc->codec_id == CODEC_ID_VP6A) 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); } avio_flush(pb); av_free(data); return pb->error; }
static int flv_write_header(AVFormatContext *s) { AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; AVCodecContext *audio_enc = NULL, *video_enc = NULL, *data_enc = NULL; int i, metadata_count = 0; double framerate = 0.0; int64_t metadata_size_pos, data_size, metadata_count_pos; AVDictionaryEntry *tag = NULL; for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; FLVStreamContext *sc; switch (enc->codec_type) { case AVMEDIA_TYPE_VIDEO: if (s->streams[i]->avg_frame_rate.den && s->streams[i]->avg_frame_rate.num) { framerate = av_q2d(s->streams[i]->avg_frame_rate); } else { framerate = 1 / av_q2d(s->streams[i]->codec->time_base); } video_enc = enc; if (enc->codec_tag == 0) { av_log(s, AV_LOG_ERROR, "video codec not compatible with flv\n"); return -1; } break; case AVMEDIA_TYPE_AUDIO: audio_enc = enc; if (get_audio_flags(s, enc) < 0) return AVERROR_INVALIDDATA; break; case AVMEDIA_TYPE_DATA: if (enc->codec_id != CODEC_ID_TEXT) { av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n"); return AVERROR_INVALIDDATA; } data_enc = enc; break; default: av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n"); return -1; } avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */ sc = av_mallocz(sizeof(FLVStreamContext)); if (!sc) return AVERROR(ENOMEM); s->streams[i]->priv_data = sc; sc->last_ts = -1; } flv->delay = AV_NOPTS_VALUE; avio_write(pb, "FLV", 3); avio_w8(pb, 1); avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!audio_enc + FLV_HEADER_FLAG_HASVIDEO * !!video_enc); avio_wb32(pb, 9); avio_wb32(pb, 0); for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->codec->codec_tag == 5) { avio_w8(pb, 8); // message type avio_wb24(pb, 0); // include flags avio_wb24(pb, 0); // time stamp avio_wb32(pb, 0); // reserved avio_wb32(pb, 11); // size flv->reserved = 5; } /* write meta_tag */ avio_w8(pb, 18); // tag type META metadata_size_pos = avio_tell(pb); avio_wb24(pb, 0); // size of data part (sum of all parts below) avio_wb24(pb, 0); // timestamp avio_wb32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); metadata_count_pos = avio_tell(pb); metadata_count = 5 * !!video_enc + 5 * !!audio_enc + 1 * !!data_enc + 2; // +2 for duration and file size avio_wb32(pb, metadata_count); put_amf_string(pb, "duration"); flv->duration_offset= avio_tell(pb); // 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_double(pb, video_enc->width); put_amf_string(pb, "height"); put_amf_double(pb, video_enc->height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, video_enc->bit_rate / 1024.0); put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); put_amf_string(pb, "videocodecid"); put_amf_double(pb, video_enc->codec_tag); } if (audio_enc) { put_amf_string(pb, "audiodatarate"); put_amf_double(pb, audio_enc->bit_rate / 1024.0); put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, audio_enc->sample_rate); put_amf_string(pb, "audiosamplesize"); put_amf_double(pb, audio_enc->codec_id == CODEC_ID_PCM_U8 ? 8 : 16); put_amf_string(pb, "stereo"); put_amf_bool(pb, audio_enc->channels == 2); put_amf_string(pb, "audiocodecid"); put_amf_double(pb, audio_enc->codec_tag); } if (data_enc) { put_amf_string(pb, "datastream"); put_amf_double(pb, 0.0); } while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { if( !strcmp(tag->key, "width") ||!strcmp(tag->key, "height") ||!strcmp(tag->key, "videodatarate") ||!strcmp(tag->key, "framerate") ||!strcmp(tag->key, "videocodecid") ||!strcmp(tag->key, "audiodatarate") ||!strcmp(tag->key, "audiosamplerate") ||!strcmp(tag->key, "audiosamplesize") ||!strcmp(tag->key, "stereo") ||!strcmp(tag->key, "audiocodecid") ||!strcmp(tag->key, "duration") ||!strcmp(tag->key, "onMetaData") ){ av_log(s, AV_LOG_DEBUG, "ignoring metadata for %s\n", tag->key); continue; } put_amf_string(pb, tag->key); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, tag->value); metadata_count++; } put_amf_string(pb, "filesize"); flv->filesize_offset = avio_tell(pb); put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); avio_w8(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size = avio_tell(pb) - metadata_size_pos - 10; avio_seek(pb, metadata_count_pos, SEEK_SET); avio_wb32(pb, metadata_count); avio_seek(pb, metadata_size_pos, SEEK_SET); avio_wb24(pb, data_size); avio_skip(pb, data_size + 10 - 3); avio_wb32(pb, data_size + 11); for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_id == CODEC_ID_AAC || enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) { int64_t pos; avio_w8(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); avio_wb24(pb, 0); // size patched later avio_wb24(pb, 0); // ts avio_w8(pb, 0); // ts ext avio_wb24(pb, 0); // streamid pos = avio_tell(pb); if (enc->codec_id == CODEC_ID_AAC) { avio_w8(pb, get_audio_flags(s, enc)); avio_w8(pb, 0); // AAC sequence header avio_write(pb, enc->extradata, enc->extradata_size); } else { avio_w8(pb, enc->codec_tag | FLV_FRAME_KEY); // flags avio_w8(pb, 0); // AVC sequence header avio_wb24(pb, 0); // composition time ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size); } data_size = avio_tell(pb) - pos; avio_seek(pb, -data_size - 10, SEEK_CUR); avio_wb24(pb, data_size); avio_skip(pb, data_size + 10 - 3); avio_wb32(pb, data_size + 11); // previous tag size } } return 0; }
static int flv_write_packet( AVFormatContext *s, AVPacket *pkt ) { LogStr("Init"); //Fernando: //printf("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n"); //printf("************* proc: %s - line: %d\n", __func__, __LINE__); //dumpPacket(&pkt); //getchar(); ByteIOContext *pb = s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; unsigned ts; int size = pkt->size; int flags, flags_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 || enc->codec_id == CODEC_ID_AAC) { flags_size = 2; } else if (enc->codec_id == CODEC_ID_H264) { flags_size = 5; } else { flags_size = 1; } if (enc->codec_type == CODEC_TYPE_VIDEO) { put_byte(pb, FLV_TAG_TYPE_VIDEO); flags = enc->codec_tag; if (flags == 0) { av_log(enc, AV_LOG_ERROR, "video codec %X not compatible with flv\n", enc->codec_id); LogStr("Exit"); return -1; } flags |= pkt->flags & PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; } else { assert(enc->codec_type == CODEC_TYPE_AUDIO); flags = get_audio_flags(enc); assert(size); put_byte(pb, FLV_TAG_TYPE_AUDIO); } if (enc->codec_id == CODEC_ID_H264 && /* check if extradata looks like mp4 formated */ enc->extradata_size > 0 && *(uint8_t*) enc->extradata != 1) { if (ff_avc_parse_nal_units(pkt->data, &pkt->data, &pkt->size) < 0) { LogStr("Exit"); return -1; } assert(pkt->size); size = pkt->size; /* cast needed to get negative value */ if (!flv->delay && pkt->dts < 0) { flv->delay = -pkt->dts; } } ts = pkt->dts + flv->delay; // add delay to force positive dts put_be24(pb, size + flags_size); put_be24(pb, ts); put_byte(pb, (ts >> 24) & 0x7F); // timestamps are 32bits _signed_ put_be24(pb, flv->reserved); put_byte(pb, flags); if (enc->codec_id == CODEC_ID_VP6) { put_byte(pb, 0); } if (enc->codec_id == CODEC_ID_VP6F) { put_byte(pb, enc->extradata_size ? enc->extradata[0] : 0); } else if (enc->codec_id == CODEC_ID_AAC) { put_byte(pb, 1); // AAC raw } else if (enc->codec_id == CODEC_ID_H264) { put_byte(pb, 1); // AVC NALU put_be24(pb, pkt->pts - pkt->dts); } put_buffer(pb, pkt->data, size); put_be32(pb, size + flags_size + 11); // previous tag size flv->duration = FFMAX(flv->duration, pkt->pts + flv->delay + pkt->duration); put_flush_packet(pb); LogStr("Exit"); return 0; }
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data; unsigned ts; int size = pkt->size; uint8_t *data = NULL; int flags = -1, flags_size, ret; if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A || enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_AAC) flags_size = 2; else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) flags_size = 5; else flags_size = 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 if (s->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) { write_metadata(s, ts); s->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED; } switch (enc->codec_type) { case AVMEDIA_TYPE_VIDEO: avio_w8(pb, FLV_TAG_TYPE_VIDEO); flags = enc->codec_tag; if (flags == 0) { av_log(s, AV_LOG_ERROR, "Video codec '%s' is not compatible with FLV\n", avcodec_get_name(enc->codec_id)); return AVERROR(EINVAL); } flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; break; case AVMEDIA_TYPE_AUDIO: flags = get_audio_flags(s, enc); av_assert0(size); avio_w8(pb, FLV_TAG_TYPE_AUDIO); break; case AVMEDIA_TYPE_SUBTITLE: case AVMEDIA_TYPE_DATA: avio_w8(pb, FLV_TAG_TYPE_META); break; default: return AVERROR(EINVAL); } if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) { /* check if extradata looks like mp4 formated */ if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0) return ret; } else if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { if (!s->streams[pkt->stream_index]->nb_frames) { av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: " "use the audio bitstream filter 'aac_adtstoasc' to fix it " "('-bsf:a aac_adtstoasc' option with ffmpeg)\n"); return AVERROR_INVALIDDATA; } av_log(s, AV_LOG_WARNING, "aac bitstream error\n"); } /* check Speex packet duration */ if (enc->codec_id == AV_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; if (size + flags_size >= 1<<24) { av_log(s, AV_LOG_ERROR, "Too large packet with size %u >= %u\n", size + flags_size, 1<<24); return AVERROR(EINVAL); } avio_wb24(pb, size + flags_size); avio_wb24(pb, ts & 0xFFFFFF); avio_w8(pb, (ts >> 24) & 0x7F); // timestamps are 32 bits _signed_ avio_wb24(pb, flv->reserved); if (enc->codec_type == AVMEDIA_TYPE_DATA || enc->codec_type == AVMEDIA_TYPE_SUBTITLE ) { int data_size; int64_t metadata_size_pos = avio_tell(pb); if (enc->codec_id == AV_CODEC_ID_TEXT) { // legacy FFmpeg magic? avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onTextData"); avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); avio_wb32(pb, 2); put_amf_string(pb, "type"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "Text"); put_amf_string(pb, "text"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, pkt->data); put_amf_string(pb, ""); avio_w8(pb, AMF_END_OF_OBJECT); } else { // just pass the metadata through avio_write(pb, data ? data : pkt->data, size); } /* write total size of tag */ data_size = avio_tell(pb) - metadata_size_pos; avio_seek(pb, metadata_size_pos - 10, SEEK_SET); avio_wb24(pb, data_size); avio_seek(pb, data_size + 10 - 3, SEEK_CUR); avio_wb32(pb, data_size + 11); } else { av_assert1(flags>=0); avio_w8(pb,flags); if (enc->codec_id == AV_CODEC_ID_VP6) avio_w8(pb,0); if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A) { if (enc->extradata_size) avio_w8(pb, enc->extradata[0]); else avio_w8(pb, ((FFALIGN(enc->width, 16) - enc->width) << 4) | (FFALIGN(enc->height, 16) - enc->height)); } else if (enc->codec_id == AV_CODEC_ID_AAC) avio_w8(pb, 1); // AAC raw else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_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); } av_free(data); return pb->error; }
static int flv_write_header(AVFormatContext *s) { int i; AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; int64_t data_size; for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; FLVStreamContext *sc; switch (enc->codec_type) { case AVMEDIA_TYPE_VIDEO: if (s->streams[i]->avg_frame_rate.den && s->streams[i]->avg_frame_rate.num) { flv->framerate = av_q2d(s->streams[i]->avg_frame_rate); } if (flv->video_enc) { av_log(s, AV_LOG_ERROR, "at most one video stream is supported in flv\n"); return AVERROR(EINVAL); } flv->video_enc = enc; if (enc->codec_tag == 0) { av_log(s, AV_LOG_ERROR, "Video codec '%s' for stream %d is not compatible with FLV\n", avcodec_get_name(enc->codec_id), i); return AVERROR(EINVAL); } if (enc->codec_id == AV_CODEC_ID_MPEG4 || enc->codec_id == AV_CODEC_ID_H263) { int error = s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL; av_log(s, error ? AV_LOG_ERROR : AV_LOG_WARNING, "Codec %s is not supported in the official FLV specification,\n", avcodec_get_name(enc->codec_id)); if (error) { av_log(s, AV_LOG_ERROR, "use vstrict=-1 / -strict -1 to use it anyway.\n"); return AVERROR(EINVAL); } } else if (enc->codec_id == AV_CODEC_ID_VP6) { av_log(s, AV_LOG_WARNING, "Muxing VP6 in flv will produce flipped video on playback.\n"); } break; case AVMEDIA_TYPE_AUDIO: if (flv->audio_enc) { av_log(s, AV_LOG_ERROR, "at most one audio stream is supported in flv\n"); return AVERROR(EINVAL); } flv->audio_enc = enc; if (get_audio_flags(s, enc) < 0) return AVERROR_INVALIDDATA; if (enc->codec_id == AV_CODEC_ID_PCM_S16BE) av_log(s, AV_LOG_WARNING, "16-bit big-endian audio in flv is valid but most likely unplayable (hardware dependent); use s16le\n"); break; case AVMEDIA_TYPE_DATA: if (enc->codec_id != AV_CODEC_ID_TEXT && enc->codec_id != AV_CODEC_ID_NONE) { av_log(s, AV_LOG_ERROR, "Data codec '%s' for stream %d is not compatible with FLV\n", avcodec_get_name(enc->codec_id), i); return AVERROR_INVALIDDATA; } flv->data_enc = enc; break; case AVMEDIA_TYPE_SUBTITLE: if (enc->codec_id != AV_CODEC_ID_TEXT) { av_log(s, AV_LOG_ERROR, "Subtitle codec '%s' for stream %d is not compatible with FLV\n", avcodec_get_name(enc->codec_id), i); return AVERROR_INVALIDDATA; } flv->data_enc = enc; break; default: av_log(s, AV_LOG_ERROR, "Codec type '%s' for stream %d is not compatible with FLV\n", av_get_media_type_string(enc->codec_type), i); return AVERROR(EINVAL); } avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */ sc = av_mallocz(sizeof(FLVStreamContext)); if (!sc) return AVERROR(ENOMEM); s->streams[i]->priv_data = sc; sc->last_ts = -1; } flv->delay = AV_NOPTS_VALUE; avio_write(pb, "FLV", 3); avio_w8(pb, 1); avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!flv->audio_enc + FLV_HEADER_FLAG_HASVIDEO * !!flv->video_enc); avio_wb32(pb, 9); avio_wb32(pb, 0); for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->codec->codec_tag == 5) { avio_w8(pb, 8); // message type avio_wb24(pb, 0); // include flags avio_wb24(pb, 0); // time stamp avio_wb32(pb, 0); // reserved avio_wb32(pb, 11); // size flv->reserved = 5; } write_metadata(s, 0); for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_id == AV_CODEC_ID_AAC || enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) { int64_t pos; avio_w8(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); avio_wb24(pb, 0); // size patched later avio_wb24(pb, 0); // ts avio_w8(pb, 0); // ts ext avio_wb24(pb, 0); // streamid pos = avio_tell(pb); if (enc->codec_id == AV_CODEC_ID_AAC) { avio_w8(pb, get_audio_flags(s, enc)); avio_w8(pb, 0); // AAC sequence header avio_write(pb, enc->extradata, enc->extradata_size); } else { avio_w8(pb, enc->codec_tag | FLV_FRAME_KEY); // flags avio_w8(pb, 0); // AVC sequence header avio_wb24(pb, 0); // composition time ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size); } data_size = avio_tell(pb) - pos; avio_seek(pb, -data_size - 10, SEEK_CUR); avio_wb24(pb, data_size); avio_skip(pb, data_size + 10 - 3); avio_wb32(pb, data_size + 11); // previous tag size } } return 0; }
static int flv_write_header(AVFormatContext *s) { int i; AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; for (i = 0; i < s->nb_streams; i++) { AVCodecParameters *par = s->streams[i]->codecpar; FLVStreamContext *sc; switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: if (s->streams[i]->avg_frame_rate.den && s->streams[i]->avg_frame_rate.num) { flv->framerate = av_q2d(s->streams[i]->avg_frame_rate); } if (flv->video_par) { av_log(s, AV_LOG_ERROR, "at most one video stream is supported in flv\n"); return AVERROR(EINVAL); } flv->video_par = par; if (!ff_codec_get_tag(flv_video_codec_ids, par->codec_id)) return unsupported_codec(s, "Video", par->codec_id); if (par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_H263) { int error = s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL; av_log(s, error ? AV_LOG_ERROR : AV_LOG_WARNING, "Codec %s is not supported in the official FLV specification,\n", avcodec_get_name(par->codec_id)); if (error) { av_log(s, AV_LOG_ERROR, "use vstrict=-1 / -strict -1 to use it anyway.\n"); return AVERROR(EINVAL); } } else if (par->codec_id == AV_CODEC_ID_VP6) { av_log(s, AV_LOG_WARNING, "Muxing VP6 in flv will produce flipped video on playback.\n"); } break; case AVMEDIA_TYPE_AUDIO: if (flv->audio_par) { av_log(s, AV_LOG_ERROR, "at most one audio stream is supported in flv\n"); return AVERROR(EINVAL); } flv->audio_par = par; if (get_audio_flags(s, par) < 0) return unsupported_codec(s, "Audio", par->codec_id); if (par->codec_id == AV_CODEC_ID_PCM_S16BE) av_log(s, AV_LOG_WARNING, "16-bit big-endian audio in flv is valid but most likely unplayable (hardware dependent); use s16le\n"); break; case AVMEDIA_TYPE_DATA: if (par->codec_id != AV_CODEC_ID_TEXT && par->codec_id != AV_CODEC_ID_NONE) return unsupported_codec(s, "Data", par->codec_id); flv->data_par = par; break; case AVMEDIA_TYPE_SUBTITLE: if (par->codec_id != AV_CODEC_ID_TEXT) { av_log(s, AV_LOG_ERROR, "Subtitle codec '%s' for stream %d is not compatible with FLV\n", avcodec_get_name(par->codec_id), i); return AVERROR_INVALIDDATA; } flv->data_par = par; break; default: av_log(s, AV_LOG_ERROR, "Codec type '%s' for stream %d is not compatible with FLV\n", av_get_media_type_string(par->codec_type), i); return AVERROR(EINVAL); } avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */ sc = av_mallocz(sizeof(FLVStreamContext)); if (!sc) return AVERROR(ENOMEM); s->streams[i]->priv_data = sc; sc->last_ts = -1; } flv->delay = AV_NOPTS_VALUE; avio_write(pb, "FLV", 3); avio_w8(pb, 1); avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!flv->audio_par + FLV_HEADER_FLAG_HASVIDEO * !!flv->video_par); avio_wb32(pb, 9); avio_wb32(pb, 0); for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->codecpar->codec_tag == 5) { avio_w8(pb, 8); // message type avio_wb24(pb, 0); // include flags avio_wb24(pb, 0); // time stamp avio_wb32(pb, 0); // reserved avio_wb32(pb, 11); // size flv->reserved = 5; } if (flv->flags & FLV_NO_METADATA) { pb->seekable = 0; } else { write_metadata(s, 0); } for (i = 0; i < s->nb_streams; i++) { flv_write_codec_header(s, s->streams[i]->codecpar); } flv->datastart_offset = avio_tell(pb); return 0; }
static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par) { int64_t data_size; AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { int64_t pos; avio_w8(pb, par->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); avio_wb24(pb, 0); // size patched later avio_wb24(pb, 0); // ts avio_w8(pb, 0); // ts ext avio_wb24(pb, 0); // streamid pos = avio_tell(pb); if (par->codec_id == AV_CODEC_ID_AAC) { avio_w8(pb, get_audio_flags(s, par)); avio_w8(pb, 0); // AAC sequence header if (!par->extradata_size && (flv->flags & FLV_AAC_SEQ_HEADER_DETECT)) { PutBitContext pbc; int samplerate_index; int channels = flv->audio_par->channels - (flv->audio_par->channels == 8 ? 1 : 0); uint8_t data[2]; for (samplerate_index = 0; samplerate_index < 16; samplerate_index++) if (flv->audio_par->sample_rate == mpeg4audio_sample_rates[samplerate_index]) break; init_put_bits(&pbc, data, sizeof(data)); put_bits(&pbc, 5, flv->audio_par->profile + 1); //profile put_bits(&pbc, 4, samplerate_index); //sample rate index put_bits(&pbc, 4, channels); put_bits(&pbc, 1, 0); //frame length - 1024 samples put_bits(&pbc, 1, 0); //does not depend on core coder put_bits(&pbc, 1, 0); //is not extension flush_put_bits(&pbc); avio_w8(pb, data[0]); avio_w8(pb, data[1]); av_log(s, AV_LOG_WARNING, "AAC sequence header: %02x %02x.\n", data[0], data[1]); } avio_write(pb, par->extradata, par->extradata_size); } else { avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags avio_w8(pb, 0); // AVC sequence header avio_wb24(pb, 0); // composition time ff_isom_write_avcc(pb, par->extradata, par->extradata_size); } data_size = avio_tell(pb) - pos; avio_seek(pb, -data_size - 10, SEEK_CUR); avio_wb24(pb, data_size); avio_skip(pb, data_size + 10 - 3); avio_wb32(pb, data_size + 11); // previous tag size } }
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; FLVContext *flv = s->priv_data; FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data; unsigned ts; int size = pkt->size; uint8_t *data = NULL; int flags = 0, flags_size; if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A || par->codec_id == AV_CODEC_ID_AAC) flags_size = 2; else if (par->codec_id == AV_CODEC_ID_H264) flags_size = 5; else flags_size = 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 if (s->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) { write_metadata(s, ts); s->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED; } switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: avio_w8(pb, FLV_TAG_TYPE_VIDEO); flags = ff_codec_get_tag(flv_video_codec_ids, par->codec_id); flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; break; case AVMEDIA_TYPE_AUDIO: flags = get_audio_flags(s, par); assert(size); avio_w8(pb, FLV_TAG_TYPE_AUDIO); break; case AVMEDIA_TYPE_DATA: avio_w8(pb, FLV_TAG_TYPE_META); break; default: return AVERROR(EINVAL); } if (par->codec_id == AV_CODEC_ID_H264) /* check if extradata looks like MP4 */ if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1) if (ff_avc_parse_nal_units_buf(pkt->data, &data, &size) < 0) return -1; /* check Speex packet duration */ if (par->codec_id == AV_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 32 bits _signed_ avio_wb24(pb, flv->reserved); if (par->codec_type == AVMEDIA_TYPE_DATA) { int data_size; int64_t metadata_size_pos = avio_tell(pb); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onTextData"); avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); avio_wb32(pb, 2); put_amf_string(pb, "type"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "Text"); put_amf_string(pb, "text"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, pkt->data); put_amf_string(pb, ""); avio_w8(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size = avio_tell(pb) - metadata_size_pos; avio_seek(pb, metadata_size_pos - 10, SEEK_SET); avio_wb24(pb, data_size); avio_seek(pb, data_size + 10 - 3, SEEK_CUR); avio_wb32(pb, data_size + 11); } else { avio_w8(pb,flags); if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A) { if (par->extradata_size) avio_w8(pb, par->extradata[0]); else avio_w8(pb, ((FFALIGN(par->width, 16) - par->width) << 4) | (FFALIGN(par->height, 16) - par->height)); } else if (par->codec_id == AV_CODEC_ID_AAC) avio_w8(pb, 1); // AAC raw else if (par->codec_id == AV_CODEC_ID_H264) { 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); } av_free(data); return pb->error; }
static int flv_write_header(AVFormatContext *s) { int i; AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; int64_t data_size; for (i = 0; i < s->nb_streams; i++) { AVCodecParameters *par = s->streams[i]->codecpar; FLVStreamContext *sc; switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: if (s->streams[i]->avg_frame_rate.den && s->streams[i]->avg_frame_rate.num) { flv->framerate = av_q2d(s->streams[i]->avg_frame_rate); } if (flv->video_par) { av_log(s, AV_LOG_ERROR, "at most one video stream is supported in flv\n"); return AVERROR(EINVAL); } flv->video_par = par; if (!ff_codec_get_tag(flv_video_codec_ids, par->codec_id)) return unsupported_codec(s, "Video", par->codec_id); break; case AVMEDIA_TYPE_AUDIO: if (flv->audio_par) { av_log(s, AV_LOG_ERROR, "at most one audio stream is supported in flv\n"); return AVERROR(EINVAL); } flv->audio_par = par; if (get_audio_flags(s, par) < 0) return unsupported_codec(s, "Audio", par->codec_id); break; case AVMEDIA_TYPE_DATA: if (par->codec_id != AV_CODEC_ID_TEXT) return unsupported_codec(s, "Data", par->codec_id); flv->data_par = par; break; default: av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n"); return -1; } avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */ sc = av_mallocz(sizeof(FLVStreamContext)); if (!sc) return AVERROR(ENOMEM); s->streams[i]->priv_data = sc; sc->last_ts = -1; } flv->delay = AV_NOPTS_VALUE; avio_write(pb, "FLV", 3); avio_w8(pb, 1); avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!flv->audio_par + FLV_HEADER_FLAG_HASVIDEO * !!flv->video_par); avio_wb32(pb, 9); avio_wb32(pb, 0); for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->codecpar->codec_tag == 5) { avio_w8(pb, 8); // message type avio_wb24(pb, 0); // include flags avio_wb24(pb, 0); // time stamp avio_wb32(pb, 0); // reserved avio_wb32(pb, 11); // size flv->reserved = 5; } write_metadata(s, 0); for (i = 0; i < s->nb_streams; i++) { AVCodecParameters *par = s->streams[i]->codecpar; if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264) { int64_t pos; avio_w8(pb, par->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); avio_wb24(pb, 0); // size patched later avio_wb24(pb, 0); // ts avio_w8(pb, 0); // ts ext avio_wb24(pb, 0); // streamid pos = avio_tell(pb); if (par->codec_id == AV_CODEC_ID_AAC) { avio_w8(pb, get_audio_flags(s, par)); avio_w8(pb, 0); // AAC sequence header avio_write(pb, par->extradata, par->extradata_size); } else { avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags avio_w8(pb, 0); // AVC sequence header avio_wb24(pb, 0); // composition time ff_isom_write_avcc(pb, par->extradata, par->extradata_size); } data_size = avio_tell(pb) - pos; avio_seek(pb, -data_size - 10, SEEK_CUR); avio_wb24(pb, data_size); avio_skip(pb, data_size + 10 - 3); avio_wb32(pb, data_size + 11); // previous tag size } } return 0; }
static int flv_write_header(AVFormatContext *s) { ByteIOContext *pb = s->pb; FLVContext *flv = s->priv_data; int i, width, height, samplerate, samplesize, channels, audiocodecid, videocodecid; double framerate = 0.0; int metadata_size_pos, data_size; flv->hasAudio = 0; flv->hasVideo = 0; for(i=0; i<s->nb_streams; i++){ AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_VIDEO) { width = enc->width; height = enc->height; if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { framerate = av_q2d(s->streams[i]->r_frame_rate); } else { framerate = 1/av_q2d(s->streams[i]->codec->time_base); } flv->hasVideo=1; videocodecid = enc->codec_tag; if(videocodecid == 0) { av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n"); return -1; } } else { flv->hasAudio=1; samplerate = enc->sample_rate; channels = enc->channels; audiocodecid = enc->codec_tag; samplesize = (enc->codec_id == CODEC_ID_PCM_S8) ? 8 : 16; if(get_audio_flags(enc)<0) return -1; } av_set_pts_info(s->streams[i], 24, 1, 1000); /* 24 bit pts in ms */ } put_tag(pb,"FLV"); put_byte(pb,1); put_byte(pb, FLV_HEADER_FLAG_HASAUDIO * flv->hasAudio + FLV_HEADER_FLAG_HASVIDEO * flv->hasVideo); put_be32(pb,9); put_be32(pb,0); for(i=0; i<s->nb_streams; i++){ if(s->streams[i]->codec->codec_tag == 5){ put_byte(pb,8); // message type put_be24(pb,0); // include flags put_be24(pb,0); // time stamp put_be32(pb,0); // reserved put_be32(pb,11); // size flv->reserved=5; } } /* write meta_tag */ put_byte(pb, 18); // tag type META metadata_size_pos= url_ftell(pb); put_be24(pb, 0); // size of data part (sum of all parts below) put_be24(pb, 0); // time stamp put_be32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ put_byte(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ put_byte(pb, AMF_DATA_TYPE_MIXEDARRAY); put_be32(pb, 5*flv->hasVideo + 4*flv->hasAudio + 2); // +2 for duration and file size put_amf_string(pb, "duration"); flv->duration_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write if(flv->hasVideo){ put_amf_string(pb, "width"); put_amf_double(pb, width); put_amf_string(pb, "height"); put_amf_double(pb, height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, s->bit_rate / 1024.0); put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); put_amf_string(pb, "videocodecid"); put_amf_double(pb, videocodecid); } if(flv->hasAudio){ put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, samplerate); put_amf_string(pb, "audiosamplesize"); put_amf_double(pb, samplesize); put_amf_string(pb, "stereo"); put_amf_bool(pb, (channels == 2)); put_amf_string(pb, "audiocodecid"); put_amf_double(pb, audiocodecid); } put_amf_string(pb, "filesize"); flv->filesize_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); put_byte(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size= url_ftell(pb) - metadata_size_pos - 10; url_fseek(pb, metadata_size_pos, SEEK_SET); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); return 0; }
static int flv_write_header(AVFormatContext *s) { ByteIOContext *pb = s->pb; FLVContext *flv = s->priv_data; AVCodecContext *audio_enc = NULL, *video_enc = NULL; int i; double framerate = 0.0; int64_t metadata_size_pos, data_size; for(i=0; i<s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { framerate = av_q2d(s->streams[i]->r_frame_rate); } else { framerate = 1/av_q2d(s->streams[i]->codec->time_base); } video_enc = enc; if(enc->codec_tag == 0) { av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n"); return -1; } } else { audio_enc = enc; if(get_audio_flags(enc)<0) return -1; } av_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */ } put_tag(pb,"FLV"); put_byte(pb,1); put_byte(pb, FLV_HEADER_FLAG_HASAUDIO * !!audio_enc + FLV_HEADER_FLAG_HASVIDEO * !!video_enc); put_be32(pb,9); put_be32(pb,0); for(i=0; i<s->nb_streams; i++) { if(s->streams[i]->codec->codec_tag == 5) { put_byte(pb,8); // message type put_be24(pb,0); // include flags put_be24(pb,0); // time stamp put_be32(pb,0); // reserved put_be32(pb,11); // size flv->reserved=5; } } /* write meta_tag */ put_byte(pb, 18); // tag type META metadata_size_pos= url_ftell(pb); put_be24(pb, 0); // size of data part (sum of all parts below) put_be24(pb, 0); // time stamp put_be32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ put_byte(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ put_byte(pb, AMF_DATA_TYPE_MIXEDARRAY); put_be32(pb, 5*!!video_enc + 5*!!audio_enc + 2); // +2 for duration and file size put_amf_string(pb, "duration"); flv->duration_offset= url_ftell(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) { put_amf_string(pb, "width"); put_amf_double(pb, video_enc->width); put_amf_string(pb, "height"); put_amf_double(pb, video_enc->height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, video_enc->bit_rate / 1024.0); put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); put_amf_string(pb, "videocodecid"); put_amf_double(pb, video_enc->codec_tag); } if(audio_enc) { put_amf_string(pb, "audiodatarate"); put_amf_double(pb, audio_enc->bit_rate / 1024.0); put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, audio_enc->sample_rate); put_amf_string(pb, "audiosamplesize"); put_amf_double(pb, audio_enc->codec_id == CODEC_ID_PCM_U8 ? 8 : 16); put_amf_string(pb, "stereo"); put_amf_bool(pb, audio_enc->channels == 2); put_amf_string(pb, "audiocodecid"); put_amf_double(pb, audio_enc->codec_tag); } put_amf_string(pb, "filesize"); flv->filesize_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); put_byte(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size= url_ftell(pb) - metadata_size_pos - 10; url_fseek(pb, metadata_size_pos, SEEK_SET); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_id == CODEC_ID_AAC || enc->codec_id == CODEC_ID_H264) { int64_t pos; put_byte(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); put_be24(pb, 0); // size patched later put_be24(pb, 0); // ts put_byte(pb, 0); // ts ext put_be24(pb, 0); // streamid pos = url_ftell(pb); if (enc->codec_id == CODEC_ID_AAC) { put_byte(pb, get_audio_flags(enc)); put_byte(pb, 0); // AAC sequence header put_buffer(pb, enc->extradata, enc->extradata_size); } else { put_byte(pb, enc->codec_tag | FLV_FRAME_KEY); // flags put_byte(pb, 0); // AVC sequence header put_be24(pb, 0); // composition time ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size); } data_size = url_ftell(pb) - pos; url_fseek(pb, -data_size - 10, SEEK_CUR); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); // previous tag size } } return 0; }
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; FLVContext *flv = s->priv_data; FLVStreamContext *sc = s->streams[pkt->stream_index]->priv_data; unsigned ts; int size = pkt->size; uint8_t *data = NULL; int flags = -1, flags_size, ret; int64_t cur_offset = avio_tell(pb); if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A || par->codec_id == AV_CODEC_ID_VP6 || par->codec_id == AV_CODEC_ID_AAC) flags_size = 2; else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) flags_size = 5; else flags_size = 1; if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { int side_size = 0; uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) { av_free(par->extradata); par->extradata = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!par->extradata) { par->extradata_size = 0; return AVERROR(ENOMEM); } memcpy(par->extradata, side, side_size); par->extradata_size = side_size; flv_write_codec_header(s, par); } } 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; if (s->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) { write_metadata(s, ts); s->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED; } avio_write_marker(pb, av_rescale(ts, AV_TIME_BASE, 1000), pkt->flags & AV_PKT_FLAG_KEY && (flv->video_par ? par->codec_type == AVMEDIA_TYPE_VIDEO : 1) ? AVIO_DATA_MARKER_SYNC_POINT : AVIO_DATA_MARKER_BOUNDARY_POINT); switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: avio_w8(pb, FLV_TAG_TYPE_VIDEO); flags = ff_codec_get_tag(flv_video_codec_ids, par->codec_id); flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; break; case AVMEDIA_TYPE_AUDIO: flags = get_audio_flags(s, par); av_assert0(size); avio_w8(pb, FLV_TAG_TYPE_AUDIO); break; case AVMEDIA_TYPE_SUBTITLE: case AVMEDIA_TYPE_DATA: avio_w8(pb, FLV_TAG_TYPE_META); break; default: return AVERROR(EINVAL); } if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { /* check if extradata looks like mp4 formatted */ if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1) if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0) return ret; } else if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { if (!s->streams[pkt->stream_index]->nb_frames) { av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: " "use the audio bitstream filter 'aac_adtstoasc' to fix it " "('-bsf:a aac_adtstoasc' option with ffmpeg)\n"); return AVERROR_INVALIDDATA; } av_log(s, AV_LOG_WARNING, "aac bitstream error\n"); } /* check Speex packet duration */ if (par->codec_id == AV_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; if (size + flags_size >= 1<<24) { av_log(s, AV_LOG_ERROR, "Too large packet with size %u >= %u\n", size + flags_size, 1<<24); return AVERROR(EINVAL); } avio_wb24(pb, size + flags_size); avio_wb24(pb, ts & 0xFFFFFF); avio_w8(pb, (ts >> 24) & 0x7F); // timestamps are 32 bits _signed_ avio_wb24(pb, flv->reserved); if (par->codec_type == AVMEDIA_TYPE_DATA || par->codec_type == AVMEDIA_TYPE_SUBTITLE ) { int data_size; int64_t metadata_size_pos = avio_tell(pb); if (par->codec_id == AV_CODEC_ID_TEXT) { // legacy FFmpeg magic? avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onTextData"); avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); avio_wb32(pb, 2); put_amf_string(pb, "type"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "Text"); put_amf_string(pb, "text"); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, pkt->data); put_amf_string(pb, ""); avio_w8(pb, AMF_END_OF_OBJECT); } else { // just pass the metadata through avio_write(pb, data ? data : pkt->data, size); } /* write total size of tag */ data_size = avio_tell(pb) - metadata_size_pos; avio_seek(pb, metadata_size_pos - 10, SEEK_SET); avio_wb24(pb, data_size); avio_seek(pb, data_size + 10 - 3, SEEK_CUR); avio_wb32(pb, data_size + 11); } else { av_assert1(flags>=0); avio_w8(pb,flags); if (par->codec_id == AV_CODEC_ID_VP6) avio_w8(pb,0); if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A) { if (par->extradata_size) avio_w8(pb, par->extradata[0]); else avio_w8(pb, ((FFALIGN(par->width, 16) - par->width) << 4) | (FFALIGN(par->height, 16) - par->height)); } else if (par->codec_id == AV_CODEC_ID_AAC) avio_w8(pb, 1); // AAC raw else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_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); } if (flv->flags & FLV_ADD_KEYFRAME_INDEX) { switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: flv->videosize += (avio_tell(pb) - cur_offset); flv->lasttimestamp = flv->acurframeindex / flv->framerate; if (pkt->flags & AV_PKT_FLAG_KEY) { double ts = flv->acurframeindex / flv->framerate; int64_t pos = cur_offset; flv->lastkeyframetimestamp = flv->acurframeindex / flv->framerate; flv->lastkeyframelocation = pos; flv_append_keyframe_info(s, flv, ts, pos); } flv->acurframeindex++; break; case AVMEDIA_TYPE_AUDIO: flv->audiosize += (avio_tell(pb) - cur_offset); break; default: av_log(s, AV_LOG_WARNING, "par->codec_type is type = [%d]\n", par->codec_type); break; } } av_free(data); return pb->error; }
static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { ByteIOContext *pb = s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; unsigned ts; int size= pkt->size; uint8_t *data= NULL; int flags, flags_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 || enc->codec_id == CODEC_ID_AAC) flags_size= 2; else if(enc->codec_id == CODEC_ID_H264) flags_size= 5; else flags_size= 1; if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { put_byte(pb, FLV_TAG_TYPE_VIDEO); flags = enc->codec_tag; if(flags == 0) { av_log(enc, AV_LOG_ERROR, "video codec %X not compatible with flv\n",enc->codec_id); return -1; } flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; } else { assert(enc->codec_type == AVMEDIA_TYPE_AUDIO); flags = get_audio_flags(enc); assert(size); put_byte(pb, FLV_TAG_TYPE_AUDIO); } if (enc->codec_id == CODEC_ID_H264) { /* 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; } if (!flv->delay && pkt->dts < 0) flv->delay = -pkt->dts; } ts = pkt->dts + flv->delay; // add delay to force positive dts put_be24(pb,size + flags_size); put_be24(pb,ts); put_byte(pb,(ts >> 24) & 0x7F); // timestamps are 32bits _signed_ put_be24(pb,flv->reserved); put_byte(pb,flags); if (enc->codec_id == CODEC_ID_VP6) put_byte(pb,0); if (enc->codec_id == CODEC_ID_VP6F) put_byte(pb, enc->extradata_size ? enc->extradata[0] : 0); else if (enc->codec_id == CODEC_ID_AAC) put_byte(pb,1); // AAC raw else if (enc->codec_id == CODEC_ID_H264) { put_byte(pb,1); // AVC NALU put_be24(pb,pkt->pts - pkt->dts); } put_buffer(pb, data ? data : pkt->data, size); put_be32(pb,size+flags_size+11); // previous tag size flv->duration = FFMAX(flv->duration, pkt->pts + flv->delay + pkt->duration); put_flush_packet(pb); av_free(data); return 0; }
static int flv_write_header(AVFormatContext *s) { ByteIOContext *pb = &s->pb; FLVContext *flv = s->priv_data; int i, width, height, samplerate; double framerate = 0.0; int metadata_size_pos, data_size; flv->hasAudio = 0; flv->hasVideo = 0; put_tag(pb,"FLV"); put_byte(pb,1); put_byte(pb,0); // delayed write put_be32(pb,9); put_be32(pb,0); for(i=0; i<s->nb_streams; i++){ AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_VIDEO) { width = enc->width; height = enc->height; if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { framerate = av_q2d(s->streams[i]->r_frame_rate); } else { framerate = 1/av_q2d(s->streams[i]->codec->time_base); } flv->hasVideo=1; } else { flv->hasAudio=1; samplerate = enc->sample_rate; } av_set_pts_info(s->streams[i], 24, 1, 1000); /* 24 bit pts in ms */ if(enc->codec_tag == 5){ put_byte(pb,8); // message type put_be24(pb,0); // include flags put_be24(pb,0); // time stamp put_be32(pb,0); // reserved put_be32(pb,11); // size flv->reserved=5; } if(enc->codec_type == CODEC_TYPE_AUDIO && get_audio_flags(enc)<0) return -1; } /* write meta_tag */ put_byte(pb, 18); // tag type META metadata_size_pos= url_ftell(pb); put_be24(pb, 0); // size of data part (sum of all parts below) put_be24(pb, 0); // time stamp put_be32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ put_byte(pb, AMF_STRING); // 1 byte put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ put_byte(pb, AMF_MIXED_ARRAY); put_be32(pb, 4*flv->hasVideo + flv->hasAudio + 2); // +2 for duration and file size put_amf_string(pb, "duration"); flv->duration_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write if(flv->hasVideo){ put_amf_string(pb, "width"); put_amf_double(pb, width); put_amf_string(pb, "height"); put_amf_double(pb, height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, s->bit_rate / 1024.0); put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); } if(flv->hasAudio){ put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, samplerate); } put_amf_string(pb, "filesize"); flv->filesize_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); put_byte(pb, 9); // end marker 1 byte /* write total size of tag */ data_size= url_ftell(pb) - metadata_size_pos - 10; url_fseek(pb, metadata_size_pos, SEEK_SET); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); return 0; }