📄 mpeg.c
字号:
put_byte(&ctx->pb, 0xff); } 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); } } /* 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++; /* only increase the stream packet number if this pack actually contains something that is specific to this stream! I.e. a dedicated header or some data.*/ if (!general_pack) 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++;}static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts){ MpegMuxContext *s = ctx->priv_data; int64_t scr; StreamInfo *stream; int i; 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;#if 0 for(i=0;i<ctx->nb_streams;i++) { stream = ctx->streams[i]->priv_data; if(scr > stream->start_pts && stream->start_pts!=AV_NOPTS_VALUE) { av_log(ctx, AV_LOG_DEBUG, "mpeg vcd: SCR above PTS (scr=%0.3f, stream index=%d, stream_pts=%0.3f).\n", scr/90000.0, i, stream->start_pts / 90000.0); } }#endif } 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; /* "Sanity hack": make sure that the SCR does not overtake the pts of buffered data that is still waiting to be written.*/ for(i=0;i<ctx->nb_streams;i++) { stream = ctx->streams[i]->priv_data; if(scr > stream->start_pts && stream->start_pts!=AV_NOPTS_VALUE) { /* av_log(ctx, AV_LOG_DEBUG, "mpeg: restricting scr to stream pts (scr=%0.3f, stream index=%d, stream_pts=%0.3f).\n", scr/90000.0, i, stream->start_pts / 90000.0); */ scr = stream->start_pts; } } } s->last_scr=scr; return scr;} static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt){ MpegMuxContext *s = ctx->priv_data; int stream_index= pkt->stream_index; int size= pkt->size; uint8_t *buf= pkt->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; pts= pkt->pts; dts= pkt->dts; if(s->is_svcd) { /* offset pts and dts slightly into the future to be able to do the compatibility fix below.*/ pts = (pts + 2) & ((1LL << 33) - 1); dts = (dts + 2) & ((1LL << 33) - 1); if (stream->packet_number == 0 && dts == pts) /* For the very first packet we want to force the DTS to be included. This increases compatibility with lots of DVD players. Since the MPEG-2 standard mandates that DTS is only written when it is different from PTS we have to move it slightly into the past.*/ dts = (dts - 2) & ((1LL << 33) - 1); } if(s->is_vcd) { /* We have to offset the PTS, so that it is consistent with the SCR. SCR starts at 36000, but the first two packs contain only padding and the first pack from the other stream, respectively, may also have been written before. So the real data starts at SCR 36000+3*1200. */ pts = (pts + 36000 + 3600) & ((1LL << 33) - 1); dts = (dts + 36000 + 3600) & ((1LL << 33) - 1); } #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 + 1; 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 it as it is usually not needed by decoders and because it complicates MPEG stream concatenation. */ //put_be32(&ctx->pb, ISO_11172_END_CODE); //put_flush_packet(&ctx->pb); for(i=0;i<ctx->nb_streams;i++) av_freep(&ctx->streams[i]->priv_data); return 0;}#endif //CONFIG_ENCODERS/*********************************************//* demux code */#define MAX_SYNC_SIZE 100000static int mpegps_probe(AVProbeData *p){ int code, c, i; code = 0xff; /* we search the first start code. If it is a packet start code, then we decide it is mpeg ps. We do not send highest value to give a chance to mpegts */ /* NOTE: the search range was restricted to avoid too many false detections */ if (p->buf_size < 6) return 0; for (i = 0; i < 20; i++) { c = p->buf[i]; code = (code << 8) | c; if ((code & 0xffffff00) == 0x100) { if (code == PACK_START_CODE || code == SYSTEM_HEADER_START_CODE || (code >= 0x1e0 && code <= 0x1ef) || (code >= 0x1c0 && code <= 0x1df) || code == PRIVATE_STREAM_2 || code == PROGRAM_STREAM_MAP || code == PRIVATE_STREAM_1 || code == PADDING_STREAM) return AVPROBE_SCORE_MAX - 2; else return 0; } } return 0;}typedef struct MpegDemuxContext { int header_state;} MpegDemuxContext;static int mpegps_read_header(AVFormatContext *s, AVFormatParameters *ap){ MpegDemuxContext *m = s->priv_data; m->header_state = 0xff; s->ctx_flags |= AVFMTCTX_NOHEADER; /* no need to do more */ return 0;}static int64_t get_pts(ByteIOContext *pb, int c){ int64_t pts; int val; if (c < 0) c = get_byte(pb); pts = (int64_t)((c >> 1) & 0x07) << 30; val = get_be16(pb); pts |= (int64_t)(val >> 1) << 15; val = get_be16(pb); pts |= (int64_t)(val >> 1); return pts;}static int find_next_start_code(ByteIOContext *pb, int *size_ptr, uint32_t *header_state){ unsigned int state, v; int val, n; state = *header_state; n = *size_ptr; while (n > 0) { if (url_feof(pb)) break; v = get_byte(pb); n--; if (state == 0x000001) { state = ((state << 8) | v) & 0xffffff; val = state; goto found; } state = ((state << 8) | v) & 0xffffff; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -