mpeg.c
来自「arm平台下的H264编码和解码源代码」· C语言 代码 · 共 1,402 行 · 第 1/3 页
C
1,402 行
/* the first pack of each stream contains only the pack header, the system header and some padding (see VCD standard p. IV-6) Add the padding size, so that the actual payload becomes 0.*/ buf_index += s->packet_size - buf_index; else { /* packet header size */ buf_index += 6; if (s->is_mpeg2) buf_index += 3; if (pts != AV_NOPTS_VALUE) { if (dts != pts) buf_index += 5 + 5; else buf_index += 5; } else { if (!s->is_mpeg2) buf_index++; } if (stream->id < 0xc0) { /* AC3/LPCM private data header */ buf_index += 4; if (stream->id >= 0xa0) { int n; buf_index += 3; /* NOTE: we round the payload size to an integer number of LPCM samples */ n = (s->packet_size - buf_index) % stream->lpcm_align; if (n) buf_index += (stream->lpcm_align - n); } } if (s->is_vcd && stream->id == AUDIO_ID) /* The VCD standard demands that 20 zero bytes follow each audio packet (see standard p. IV-8).*/ buf_index+=20; } return s->packet_size - buf_index; }/* Write an MPEG padding packet header. */static int put_padding_header(AVFormatContext *ctx,uint8_t* buf, int full_padding_size){ MpegMuxContext *s = ctx->priv_data; int size = full_padding_size - 6; /* subtract header length */ buf[0] = (uint8_t)(PADDING_STREAM >> 24); buf[1] = (uint8_t)(PADDING_STREAM >> 16); buf[2] = (uint8_t)(PADDING_STREAM >> 8); buf[3] = (uint8_t)(PADDING_STREAM); buf[4] = (uint8_t)(size >> 8); buf[5] = (uint8_t)(size & 0xff); if (!s->is_mpeg2) { buf[6] = 0x0f; return 7; } else return 6;}static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes){ uint8_t buffer[7]; int size, i; size = put_padding_header(ctx,buffer, packet_bytes); put_buffer(pb, buffer, size); packet_bytes -= size; for(i=0;i<packet_bytes;i++) put_byte(pb, 0xff);}/* flush the packet on stream stream_index */static void flush_packet(AVFormatContext *ctx, int stream_index, int64_t pts, int64_t dts, int64_t scr){ MpegMuxContext *s = ctx->priv_data; StreamInfo *stream = ctx->streams[stream_index]->priv_data; uint8_t *buf_ptr; int size, payload_size, startcode, id, stuffing_size, i, header_len; int packet_size; uint8_t buffer[128]; int zero_trail_bytes = 0; int pad_packet_bytes = 0; id = stream->id; #if 0 printf("packet ID=%2x PTS=%0.3f\n", id, pts / 90000.0);#endif buf_ptr = buffer; if (((s->packet_number % s->pack_header_freq) == 0)) { /* output pack and systems header if needed */ size = put_pack_header(ctx, buf_ptr, scr); buf_ptr += size; if (s->is_vcd) { /* there is exactly one system header for each stream in a VCD MPEG, One in the very first video packet and one in the very first audio packet (see VCD standard p. IV-7 and IV-8).*/ if (stream->packet_number==0) { size = put_system_header(ctx, buf_ptr, id); buf_ptr += size; } } else { if ((s->packet_number % s->system_header_freq) == 0) { size = put_system_header(ctx, buf_ptr, 0); buf_ptr += size; } } } size = buf_ptr - buffer; put_buffer(&ctx->pb, buffer, size); packet_size = s->packet_size - size; if (s->is_vcd && id == AUDIO_ID) /* The VCD standard demands that 20 zero bytes follow each audio pack (see standard p. IV-8).*/ zero_trail_bytes += 20; if (s->is_vcd && stream->packet_number==0) { /* the first pack of each stream contains only the pack header, the system header and lots of padding (see VCD standard p. IV-6). In the case of an audio pack, 20 zero bytes are also added at the end.*/ pad_packet_bytes = packet_size - zero_trail_bytes; } packet_size -= pad_packet_bytes + zero_trail_bytes; if (packet_size > 0) { /* packet header size */ packet_size -= 6; /* packet header */ if (s->is_mpeg2) { header_len = 3; } else { header_len = 0; } if (pts != AV_NOPTS_VALUE) { if (dts != pts) header_len += 5 + 5; else header_len += 5; } else { if (!s->is_mpeg2) header_len++; } payload_size = packet_size - header_len; if (id < 0xc0) { startcode = PRIVATE_STREAM_1; payload_size -= 4; if (id >= 0xa0) payload_size -= 3; } else { startcode = 0x100 + id; } stuffing_size = payload_size - stream->buffer_ptr; if (stuffing_size < 0) stuffing_size = 0; put_be32(&ctx->pb, startcode); put_be16(&ctx->pb, packet_size); if (!s->is_mpeg2) for(i=0;i<stuffing_size;i++) put_byte(&ctx->pb, 0xff); if (s->is_mpeg2) { put_byte(&ctx->pb, 0x80); /* mpeg2 id */ if (pts != AV_NOPTS_VALUE) { if (dts != pts) { put_byte(&ctx->pb, 0xc0); /* flags */ put_byte(&ctx->pb, header_len - 3 + stuffing_size); put_timestamp(&ctx->pb, 0x03, pts); put_timestamp(&ctx->pb, 0x01, dts); } else { put_byte(&ctx->pb, 0x80); /* flags */ put_byte(&ctx->pb, header_len - 3 + stuffing_size); put_timestamp(&ctx->pb, 0x02, pts); } } else { put_byte(&ctx->pb, 0x00); /* flags */ put_byte(&ctx->pb, header_len - 3 + stuffing_size); } } else { if (pts != AV_NOPTS_VALUE) { if (dts != pts) { put_timestamp(&ctx->pb, 0x03, pts); put_timestamp(&ctx->pb, 0x01, dts); } else { put_timestamp(&ctx->pb, 0x02, pts); } } else { put_byte(&ctx->pb, 0x0f); } } if (startcode == PRIVATE_STREAM_1) { put_byte(&ctx->pb, id); if (id >= 0xa0) { /* LPCM (XXX: check nb_frames) */ put_byte(&ctx->pb, 7); put_be16(&ctx->pb, 4); /* skip 3 header bytes */ put_byte(&ctx->pb, stream->lpcm_header[0]); put_byte(&ctx->pb, stream->lpcm_header[1]); put_byte(&ctx->pb, stream->lpcm_header[2]); } else { /* AC3 */ put_byte(&ctx->pb, stream->nb_frames); put_be16(&ctx->pb, stream->frame_start_offset); } } if (s->is_mpeg2) for(i=0;i<stuffing_size;i++) put_byte(&ctx->pb, 0xff); /* output data */ put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size); } if (pad_packet_bytes > 0) put_padding_packet(ctx,&ctx->pb, pad_packet_bytes); for(i=0;i<zero_trail_bytes;i++) put_byte(&ctx->pb, 0x00); put_flush_packet(&ctx->pb); s->packet_number++; stream->packet_number++; stream->nb_frames = 0; stream->frame_start_offset = 0;}static void put_vcd_padding_sector(AVFormatContext *ctx){ /* There are two ways to do this padding: writing a sector/pack of 0 values, or writing an MPEG padding pack. Both seem to work with most decoders, BUT the VCD standard only allows a 0-sector (see standard p. IV-4, IV-5). So a 0-sector it is...*/ MpegMuxContext *s = ctx->priv_data; int i; for(i=0;i<s->packet_size;i++) put_byte(&ctx->pb, 0); s->vcd_padding_bytes_written += s->packet_size; put_flush_packet(&ctx->pb); /* increasing the packet number is correct. The SCR of the following packs is calculated from the packet_number and it has to include the padding sector (it represents the sector index, not the MPEG pack index) (see VCD standard p. IV-6)*/ s->packet_number++;}/* XXX: move that to upper layer *//* XXX: we assume that there are always 'max_b_frames' between reference frames. A better solution would be to use the AVFrame pts field */static void compute_pts_dts(AVStream *st, int64_t *ppts, int64_t *pdts, int64_t timestamp){ int frame_delay; int64_t pts, dts; if (st->codec.codec_type == CODEC_TYPE_VIDEO && st->codec.max_b_frames != 0) { frame_delay = (st->codec.frame_rate_base * 90000LL) / st->codec.frame_rate; if (timestamp == 0) { /* specific case for first frame : DTS just before */ pts = timestamp; dts = timestamp - frame_delay; } else { timestamp -= frame_delay; if (st->codec.coded_frame->pict_type == FF_B_TYPE) { /* B frames has identical pts/dts */ pts = timestamp; dts = timestamp; } else { /* a reference frame has a pts equal to the dts of the _next_ one */ dts = timestamp; pts = timestamp + (st->codec.max_b_frames + 1) * frame_delay; } }#if 1 av_log(&st->codec, AV_LOG_DEBUG, "pts=%0.3f dts=%0.3f pict_type=%c\n", pts / 90000.0, dts / 90000.0, av_get_pict_type_char(st->codec.coded_frame->pict_type));#endif } else { pts = timestamp; dts = timestamp; } *ppts = pts & ((1LL << 33) - 1); *pdts = dts & ((1LL << 33) - 1);}static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts){ MpegMuxContext *s = ctx->priv_data; int64_t scr; if (s->is_vcd) /* Since the data delivery rate is constant, SCR is computed using the formula C + i * 1200 where C is the start constant and i is the pack index. It is recommended that SCR 0 is at the beginning of the VCD front margin (a sequence of empty Form 2 sectors on the CD). It is recommended that the front margin is 30 sectors long, so we use C = 30*1200 = 36000 (Note that even if the front margin is not 30 sectors the file will still be correct according to the standard. It just won't have the "recommended" value).*/ scr = 36000 + s->packet_number * 1200; else { /* XXX I believe this calculation of SCR is wrong. SCR specifies at which time the data should enter the decoder. Two packs cannot enter the decoder at the same time. */ /* XXX: system clock should be computed precisely, especially for CBR case. The current mode gives at least something coherent */ if (stream_index == s->scr_stream_index && pts != AV_NOPTS_VALUE) scr = pts; else scr = s->last_scr; } s->last_scr=scr; return scr;} static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, const uint8_t *buf, int size, int64_t timestamp){ MpegMuxContext *s = ctx->priv_data; AVStream *st = ctx->streams[stream_index]; StreamInfo *stream = st->priv_data; int64_t pts, dts, new_start_pts, new_start_dts; int len, avail_size; compute_pts_dts(st, &pts, &dts, timestamp); #if 0 update_scr(ctx,stream_index,pts); printf("%d: pts=%0.3f dts=%0.3f scr=%0.3f\n", stream_index, pts / 90000.0, dts / 90000.0, s->last_scr / 90000.0);#endif /* we assume here that pts != AV_NOPTS_VALUE */ new_start_pts = stream->start_pts; new_start_dts = stream->start_dts; if (stream->start_pts == AV_NOPTS_VALUE) { new_start_pts = pts; new_start_dts = dts; } avail_size = get_packet_payload_size(ctx, stream_index, new_start_pts, new_start_dts); if (stream->buffer_ptr >= avail_size) { update_scr(ctx,stream_index,stream->start_pts); /* unlikely case: outputing the pts or dts increase the packet size so that we cannot write the start of the next packet. In this case, we must flush the current packet with padding. Note: this always happens for the first audio and video packet in a VCD file, since they do not carry any data.*/ flush_packet(ctx, stream_index, stream->start_pts, stream->start_dts, s->last_scr); stream->buffer_ptr = 0; } stream->start_pts = new_start_pts; stream->start_dts = new_start_dts; stream->nb_frames++; if (stream->frame_start_offset == 0) stream->frame_start_offset = stream->buffer_ptr; while (size > 0) { avail_size = get_packet_payload_size(ctx, stream_index, stream->start_pts, stream->start_dts); len = avail_size - stream->buffer_ptr; if (len > size) len = size; memcpy(stream->buffer + stream->buffer_ptr, buf, len); stream->buffer_ptr += len; buf += len; size -= len; if (stream->buffer_ptr >= avail_size) { update_scr(ctx,stream_index,stream->start_pts); /* if packet full, we send it now */ flush_packet(ctx, stream_index, stream->start_pts, stream->start_dts, s->last_scr); stream->buffer_ptr = 0; if (s->is_vcd) { /* Write one or more padding sectors, if necessary, to reach the constant overall bitrate.*/ int vcd_pad_bytes; while((vcd_pad_bytes = get_vcd_padding_size(ctx,stream->start_pts) ) >= s->packet_size) put_vcd_padding_sector(ctx); } /* Make sure only the FIRST pes packet for this frame has a timestamp */ stream->start_pts = AV_NOPTS_VALUE; stream->start_dts = AV_NOPTS_VALUE; } } return 0;}static int mpeg_mux_end(AVFormatContext *ctx){ MpegMuxContext *s = ctx->priv_data; StreamInfo *stream; int i; /* flush each packet */ for(i=0;i<ctx->nb_streams;i++) { stream = ctx->streams[i]->priv_data; if (stream->buffer_ptr > 0) { update_scr(ctx,i,stream->start_pts); /* NOTE: we can always write the remaining data as it was tested before in mpeg_mux_write_packet() */ flush_packet(ctx, i, stream->start_pts, stream->start_dts, s->last_scr); } } /* End header according to MPEG1 systems standard. We do not write
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?