muxer_mpeg.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 2,496 行 · 第 1/5 页
C
2,496 行
//headers+frame 0 < space available including timestamps if(start + pes_hlen + m < priv->packet_size - threshold) i = 1; else i = -1; } } if(i > -1) { dpts = FFMAX(spriv->last_saved_pts, spriv->framebuf[i].pts) - FFMIN(spriv->last_saved_pts, spriv->framebuf[i].pts) + spriv->framebuf[0].idur; if(s->type != MUXER_TYPE_VIDEO) ret = 1; else if((spriv->framebuf[i].type == I_FRAME || priv->ts_allframes || dpts >= 36000*300)) //0.4 seconds ret = 1; if(ret) { *pts = spriv->framebuf[i].pts; *dts = spriv->framebuf[i].dts; if(*dts == *pts) *dts = 0; } }fail: spriv->pts = spts; spriv->dts = sdts; return ret;}static int get_packet_stats(muxer_priv_t *priv, muxer_stream_t *s, pack_stats_t *p, int finalize){ muxer_headers_t *spriv = s->priv; int len, len2, pack_hlen, pes_hlen, hlen, target, stflen, stuffing_len; uint64_t pts, dts; spriv->pts = spriv->dts = 0; p->dts = p->pts = p->frame_pts = p->frame_dts = 0; p->len = 0; if(priv->rawpes) pack_hlen = 0; else if(priv->mux == MUX_MPEG1) pack_hlen = 12; else pack_hlen = 14; if(find_packet_timestamps(priv, s, pack_hlen, &dts, &pts)) { p->pts = p->frame_pts = pts; p->dts = p->frame_dts = dts; spriv->pts = pts; spriv->dts = dts; } pes_hlen = calc_pes_hlen(priv->mux, spriv, priv); p->stflen = stflen = (spriv->min_pes_hlen > pes_hlen ? spriv->min_pes_hlen - pes_hlen : 0); target = len = priv->packet_size - pack_hlen - pes_hlen - stflen; //max space available if(s->type == MUXER_TYPE_AUDIO && s->wf->wFormatTag == AUDIO_A52) hlen = 4; else hlen = 0; len -= hlen; target -= hlen; len2 = calc_packet_len(s, target, finalize); if(!len2 || (len2 < target && s->type == MUXER_TYPE_AUDIO && !finalize)) { //p->len = 0; //p->dts = p->pts = 0; spriv->pts = spriv->dts = 0; //fprintf(stderr, "\r\nLEN2: %d, target: %d, type: %d\r\n", len2, target, s->type); return 0; } len = len2; stuffing_len = 0; if(len < target) { if(s->type == MUXER_TYPE_VIDEO) { if(spriv->pts) target += 5; if(spriv->dts) target += 5; spriv->pts = spriv->dts = 0; p->pts = p->dts = 0; } stuffing_len = target - len; if(stuffing_len > 0 && stuffing_len < 7) { if(stflen + stuffing_len > 16) { int x = 7 - stuffing_len; stflen -= x; stuffing_len += x; } else { stflen += stuffing_len; stuffing_len = 0; } } } len += hlen; p->len = len; p->stflen = stflen; return p->len;}static int fill_packet(muxer_t *muxer, muxer_stream_t *s, int finalize){ //try to fill a packet as much as possible //spriv->pack_offset is the start position inited to 0 //data is taken from spriv->framebuf //if audio and a52 insert the headers muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; muxer_headers_t *spriv = (muxer_headers_t *) s->priv; int len, m, n, dvd_pack = 0; mpeg_frame_t *frm; pack_stats_t p; spriv->dts = spriv->pts = 0; if(! spriv->framebuf_used) { spriv->pack_offset = 0; return 0; } if(!spriv->pack_offset) { if(priv->rawpes) spriv->pack_offset = 0; else spriv->pack_offset = write_mpeg_pack_header(muxer, spriv->pack); if(priv->update_system_header && (priv->is_genmpeg1 || priv->is_genmpeg2)) { spriv->pack_offset += write_mpeg_system_header(muxer, &spriv->pack[spriv->pack_offset]); priv->update_system_header = 0; } spriv->pes_set = 0; spriv->pes_offset = spriv->pack_offset; spriv->payload_offset = 0; spriv->frames = 0; spriv->last_frame_rest = 0; } if(!spriv->pes_set) { int bufsize = 0; //search the pts. yes if either it's video && (I-frame or priv->ts_allframes) && framebuf[i].pos == 0 //or it's audio && framebuf[i].pos == 0 //NB pts and dts can only be relative to the first frame beginning in this pack if((priv->is_xsvcd || priv->is_xvcd || priv->rawpes) && spriv->size == 0) { if(s->type == MUXER_TYPE_VIDEO) bufsize = (conf_vbuf_size ? conf_vbuf_size : (priv->is_xvcd ? 46 : 232)); else bufsize = (conf_abuf_size ? conf_abuf_size : 4); spriv->buffer_size = bufsize*1024; } if(priv->is_dvd && s->type == MUXER_TYPE_VIDEO && spriv->framebuf[0].type==I_FRAME && spriv->framebuf[0].pos==0) dvd_pack = 1; if(! get_packet_stats(priv, s, &p, finalize)) { spriv->pack_offset = 0; return 0; } spriv->dts = p.dts; spriv->pts = p.pts; if(spriv->pts) spriv->last_saved_pts = p.pts; spriv->pack_offset += write_mpeg_pes_header(spriv, (uint8_t *) &s->ckid, &(spriv->pack[spriv->pack_offset]), p.len, p.stflen, priv->mux); if(s->type == MUXER_TYPE_AUDIO && s->wf->wFormatTag == AUDIO_A52) { spriv->payload_offset = spriv->pack_offset; spriv->pack_offset += 4; //for the 4 bytes of header if(!spriv->framebuf[0].pos) spriv->last_frame_rest = 0; else spriv->last_frame_rest = spriv->framebuf[0].size - spriv->framebuf[0].pos; } spriv->pes_set = 1; } if(spriv->dts || spriv->pts) { if((spriv->dts && priv->scr >= spriv->dts) || priv->scr >= spriv->pts) mp_msg(MSGT_MUXER, MSGL_ERR, "\r\nERROR: scr %.3lf, dts %.3lf, pts %.3lf\r\n", (double) priv->scr/27000000.0, (double) spriv->dts/27000000.0, (double) spriv->pts/27000000.0); else if(priv->scr + 63000*300 < spriv->dts) mp_msg(MSGT_MUXER, MSGL_INFO, "\r\nWARNING>: scr %.3lf, dts %.3lf, pts %.3lf, diff %.3lf, piff %.3lf\r\n", (double) priv->scr/27000000.0, (double) spriv->dts/27000000.0, (double) spriv->pts/27000000.0, (double)(spriv->dts - priv->scr)/27000000.0, (double)(spriv->pts - priv->scr)/27000000.0); } n = 0; len = 0; frm = spriv->framebuf; while(spriv->pack_offset < priv->packet_size && n < spriv->framebuf_used) { if(!frm->pos) { //since iframes must always be aligned at block boundaries exit when we find the //beginning of one in the middle of the flush if(len > 0 && s->type == MUXER_TYPE_VIDEO && frm->type == I_FRAME) { break; } spriv->frames++; update_demux_bufsize(spriv, frm->dts, frm->size, s->type); } m = FFMIN(frm->size - frm->pos, priv->packet_size - spriv->pack_offset); memcpy(&(spriv->pack[spriv->pack_offset]), &(frm->buffer[frm->pos]), m); len += m; spriv->pack_offset += m; frm->pos += m; if(frm->pos == frm->size) //end of frame { frm->pos = frm->size = 0; frm->pts = frm->dts = 0; n++; frm++; } } if((priv->is_xsvcd || priv->is_xvcd || priv->rawpes) && spriv->size == 0) spriv->buffer_size = 0; spriv->size += len; if(dvd_pack && (spriv->pack_offset == priv->packet_size)) write_mpeg_pack(muxer, NULL, muxer->stream, 0); //insert fake Nav Packet if(n > 0) remove_frames(spriv, n); spriv->track_bufsize += len; if(spriv->track_bufsize > spriv->max_buffer_size) mp_msg(MSGT_MUXER, MSGL_ERR, "\r\nBUFFER OVERFLOW: %d > %d, pts: %"PRIu64"\r\n", spriv->track_bufsize, spriv->max_buffer_size, spriv->pts); if(s->type == MUXER_TYPE_AUDIO && s->wf->wFormatTag == AUDIO_A52) fix_a52_headers(s); if(spriv->pack_offset < priv->packet_size && !priv->rawpes) //here finalize is set { int diff = priv->packet_size - spriv->pack_offset; write_pes_padding(&(spriv->pack[spriv->pack_offset]), diff); spriv->pack_offset += diff; } stream_write_buffer(muxer->stream, spriv->pack, spriv->pack_offset); priv->headers_size += spriv->pack_offset - len; priv->data_size += len; muxer->movi_end += spriv->pack_offset; spriv->pack_offset = 0; spriv->pes_set = 0; spriv->frames = 0; return len;}static inline int find_best_stream(muxer_t *muxer){ int i, ndts; uint64_t dts = -1; muxer_priv_t *priv = muxer->priv; muxer_headers_t *spriv; pack_stats_t p; unsigned int perc, sperc; ndts = -1; perc = -1; //THIS RULE MUST ALWAYS apply: dts <= SCR + 0.7 seconds for(i = 0; i < muxer->avih.dwStreams; i++) { spriv = muxer->streams[i]->priv; p.len = 0; get_packet_stats(priv, muxer->streams[i], &p, 0); if(spriv->track_bufsize + p.len > spriv->max_buffer_size) continue; if(p.frame_pts && p.frame_dts > priv->scr + 63000*300) continue; if(spriv->framebuf[0].dts <= dts) { dts = spriv->framebuf[0].dts; ndts = i; } if(conf_interleaving2) { sperc = (spriv->track_bufsize * 1024) / spriv->max_buffer_size; if(sperc < perc) { ndts = i; perc = sperc; } } } return ndts;}static void patch_seq(muxer_priv_t *priv, unsigned char *buf){ if(priv->vwidth > 0) { buf[4] = (priv->vwidth >> 4) & 0xff; buf[5] &= 0x0f; buf[5] |= (priv->vwidth & 0x0f) << 4; } if(priv->vheight > 0) { buf[5] &= 0xf0; buf[5] |= (priv->vheight >> 8) & 0x0f; buf[6] = priv->vheight & 0xff; } if(priv->vaspect > 0) buf[7] = (buf[7] & 0x0f) | (priv->vaspect << 4); if(priv->vframerate > 0) buf[7] = (buf[7] & 0xf0) | priv->vframerate; if(priv->vbitrate > 0) { buf[8] = (priv->vbitrate >> 10); buf[9] = (priv->vbitrate >> 2); buf[10] = (buf[10] & 0x3f) | (unsigned char) ((priv->vbitrate & 0x4) << 2); }}static void patch_panscan(muxer_priv_t *priv, unsigned char *buf){ //patches sequence display extension (display_horizontal_size and display_vertical_size) //1: int offset = 1; if(buf[0] & 0x01) offset += 3; if(priv->panscan_width > 0) { buf[offset] = (priv->panscan_width >> 6); buf[offset+1] = ((priv->panscan_width & 0x3F) << 2) | (buf[offset + 1] & 0x03); } offset++; if(priv->panscan_height > 0) { buf[offset] = (priv->panscan_height >> 13) << 7; buf[offset+1] = (priv->panscan_height >> 5) & 0xFF; buf[offset+2] = ((priv->panscan_height & 0x1F) << 3) | (buf[offset+2] & 0x07); }}static void update_scr(muxer_t *muxer){ muxer_priv_t *priv = muxer->priv; muxer_stream_t *stream; muxer_headers_t *spriv; int i, j; uint64_t mindts = (uint64_t) -1; priv->scr += priv->delta_scr; for(i = 0; i < muxer->avih.dwStreams; i++) { stream = muxer->streams[i]; spriv = stream->priv; if(spriv->framebuf_used && spriv->framebuf[0].dts < mindts) mindts = spriv->framebuf[0].dts; } mp_msg(MSGT_MUXER, MSGL_DBG2, "UPDATE SCR TO %"PRIu64" (%.3lf)\n", priv->scr, (double) (priv->scr/27000000.0)); for(i = 0; i < muxer->avih.dwStreams; i++) { stream = muxer->streams[i]; spriv = stream->priv; j = 0; while(j < spriv->track_pos && priv->scr >= spriv->buffer_track[j].dts) { spriv->track_bufsize -= spriv->buffer_track[j].size; j++; } if(spriv->track_bufsize < 0) { double d; muxer->sysrate = (muxer->sysrate * 11) / 10; //raise by 10% d = (double) priv->packet_size / (double)muxer->sysrate; priv->delta_scr = (uint64_t) (d * 27000000.0f); mp_msg(MSGT_MUXER, MSGL_INFO, "\r\nBUFFER UNDEFLOW at stream %d, raising muxrate to %d kb/s, delta_scr: %"PRIu64"\r\n", i, muxer->sysrate/125, priv->delta_scr); spriv->track_bufsize = 0; } if(j > 0) { memmove(spriv->buffer_track, &(spriv->buffer_track[j]), (spriv->track_len - j) * sizeof(buffer_track_t)); spriv->track_pos -= j; for(j = spriv->track_pos; j < spriv->track_len; j++) spriv->buffer_track[j].size = 0; } if(spriv->framebuf_used && spriv->framebuf[0].dts < mindts) mindts = spriv->framebuf[0].dts; }}static int calc_frames_to_flush(muxer_headers_t *vpriv){ int n, found = 0; if(vpriv->framebuf_used > 0) { n = 0; //let's count how many frames we'll store in the next pack sequence mp_msg(MSGT_MUXER, MSGL_DBG2, "\n"); while(n < vpriv->framebuf_used) { mp_msg(MSGT_MUXER, MSGL_DBG2, "CALC_FRAMES, n=%d, type=%c, pts=%.3lf\n", n, FTYPE(vpriv->framebuf[n].type), (double)vpriv->framebuf[n].pts/27000000.0f); if(n+1 < vpriv->framebuf_used) mp_msg(MSGT_MUXER, MSGL_DBG2, "n+1=%d, type=%c, pts=%.3lf\n", n+1, FTYPE(vpriv->framebuf[n+1].type), (double)vpriv->framebuf[n+1].pts/27000000.0f); if(vpriv->framebuf[n].type == I_FRAME) { if(n > 0) { found = 1; break; } } n++; } } if(found && (n < vpriv->framebuf_used+1)) return n; else return 0;}static int flush_buffers(muxer_t *muxer, int finalize){ int i, n, found; int skip_cnt; uint64_t init_delay = 0; muxer_stream_t *s, *vs, *as; muxer_headers_t *vpriv = NULL, *apriv = NULL; muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; double duration; uint64_t iduration, iaduration; /* analyzes all streams and decides what to flush trying to respect an interleaving distribution equal to the v_bitrate/a_bitrate proportion */ n = 0; vs = as = NULL; found = 0; for(i = 0; i < muxer->avih.dwStreams; i++) { s = muxer->streams[i]; if(s->type == MUXER_TYPE_VIDEO) { vs = muxer->streams[i]; vpriv = (muxer_headers_t*) vs->priv;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?