muxer_mpeg.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 2,496 行 · 第 1/5 页
C
2,496 行
if(!vpriv->is_ready) return 0; n = found = calc_frames_to_flush(vpriv); } else if(s->type == MUXER_TYPE_AUDIO) as = s; } if((! found) && finalize) { if(vpriv != NULL) found = n = vpriv->framebuf_used; } if(found) { mp_msg(MSGT_MUXER, MSGL_DBG2, "\nVIDEO, FLUSH %d frames (of %d), 0 to %d\n", n, vpriv->framebuf_used, n-1); vpriv = (muxer_headers_t*) vs->priv; duration = 0; iduration = 0; for(i = 0; i < n; i++) iduration += vpriv->framebuf[i].idur; duration = (double) (iduration / 27000000.0); if(as != NULL) { apriv = (muxer_headers_t*) as->priv; iaduration = 0; for(i = 0; i < apriv->framebuf_used; i++) { iaduration += apriv->framebuf[i].idur; } if(iaduration < iduration) { mp_msg(MSGT_MUXER, MSGL_DBG2, "Not enough audio data exit\n"); return 0; } } if(as != NULL && (apriv->size == 0)) { init_delay = vpriv->framebuf[0].pts - vpriv->framebuf[0].dts; for(i = 0; i < apriv->framebuf_cnt; i++) { apriv->framebuf[i].pts += init_delay; apriv->framebuf[i].dts += init_delay; } apriv->last_pts += init_delay; mp_msg(MSGT_MUXER, MSGL_DBG2, "\r\nINITIAL VIDEO DELAY: %.3lf, currAPTS: %.3lf\r\n", (double) init_delay/27000000.0f, (double) apriv->last_pts/27000000.0f); } if((priv->is_xvcd || priv->is_xsvcd) && (vpriv->size == 0)) vpriv->buffer_size = (conf_vbuf_size ? conf_vbuf_size : (priv->is_xvcd ? 46 : 230))*1024; i = 0; skip_cnt = 0; while(1) { update_scr(muxer); i = find_best_stream(muxer); if(i < 0) continue; if(!fill_packet(muxer, muxer->streams[i], finalize)) skip_cnt++; if(skip_cnt == muxer->avih.dwStreams) { found = 0; break; } } } muxer->file_end = priv->scr; return found;}static inline uint64_t parse_fps(float fps){ // 90000 * 300 * 1001 / d , there's no rounding error with any of the admitted framerates int d = (int)(fps*1001+0.5); return 27027000000ULL / d;}static int soft_telecine(muxer_priv_t *priv, muxer_headers_t *vpriv, uint8_t *fps_ptr, uint8_t *se_ptr, uint8_t *pce_ptr, int n){ if(! pce_ptr) return 0; if(fps_ptr != NULL) { *fps_ptr = (*fps_ptr & 0xf0) | priv->vframerate; vpriv->nom_delta_pts = parse_fps(conf_vframerate); } //in pce_ptr starting from bit 0 bit 24 is tff, bit 30 is rff, if(pce_ptr[3] & 0x2) { mp_msg(MSGT_MUXER, MSGL_ERR, "\nERROR! RFF bit is already set, disabling telecining\n"); vpriv->telecine = 0; return 0; } vpriv->picture.progressive_sequence = 0; vpriv->picture.progressive_frame = 1; if(se_ptr) se_ptr[1] &= 0xf7; //disable tff and rff and overwrite them with the value in bff_mask pce_ptr[3] = (pce_ptr[3] & 0x7d) | bff_mask[vpriv->display_frame % MAX_PATTERN_LENGTH]; pce_ptr[4] |= 0x80; //sets progressive frame vpriv->display_frame += n; if(! vpriv->vframes) mp_msg(MSGT_MUXER, MSGL_INFO, "\nENABLED SOFT TELECINING, FPS=%.3f\n",conf_vframerate); return 1;}static size_t parse_mpeg12_video(muxer_stream_t *s, muxer_priv_t *priv, muxer_headers_t *spriv, float fps, size_t len){ uint8_t *fps_ptr = NULL; //pointer to the fps byte in the sequence header uint8_t *se_ptr = NULL; //pointer to sequence extension uint8_t *pce_ptr = NULL; //pointer to picture coding extension int frames_diff, d1, gop_reset = 0; //how any frames we advanced respect to the last one int ret; int i, err; uint32_t temp_ref; int pt; mp_msg(MSGT_MUXER, MSGL_DBG2,"parse_mpeg12_video, len=%u\n", (uint32_t) len); if(s->buffer[0] != 0 || s->buffer[1] != 0 || s->buffer[2] != 1 || len<6) { mp_msg(MSGT_MUXER, MSGL_ERR,"Unknown video format, possibly non-MPEG1/2 stream, len=%d!\n", len); return 0; } temp_ref = 0; pt = 0; err = 0; i = 0; while(i + 4 < len) { // Video (0) Sequence header (b3) or GOP (b8) if((s->buffer[i] == 0) && (s->buffer[i+1] == 0) && (s->buffer[i+2] == 1)) { switch(s->buffer[i+3]) { case 0xb3: //sequence { if(i + 11 > len) { err=1; break; } fps_ptr = &(s->buffer[i+7]); mp_header_process_sequence_header(&(spriv->picture), &(s->buffer[i+4])); spriv->delta_pts = spriv->nom_delta_pts = parse_fps(spriv->picture.fps); spriv->delta_clock = (double) 1/fps; //the 2 lines below are needed to handle non-standard frame rates (such as 18) if(! spriv->delta_pts) spriv->delta_pts = spriv->nom_delta_pts = (uint64_t) ((double)27000000.0 * spriv->delta_clock ); mp_msg(MSGT_MUXER, MSGL_DBG2, "\nFPS: %.3f, FRAMETIME: %.3lf\n", fps, (double)1/fps); if(priv->patch_seq) patch_seq(priv, &(s->buffer[i])); } break; case 0xb5: if(i + 9 > len) { err = 1; break; } mp_header_process_extension(&(spriv->picture), &(s->buffer[i+4])); if(((s->buffer[i+4] & 0xf0) == 0x10)) se_ptr = &(s->buffer[i+4]); if(((s->buffer[i+4] & 0xf0) == 0x20)) { if(priv->patch_sde) patch_panscan(priv, &(s->buffer[i+4])); } if((s->buffer[i+4] & 0xf0) == 0x80) { pce_ptr = &(s->buffer[i+4]); } break; case 0xb8: gop_reset = 1; break; case 0x00: if(i + 5 > len) { err = 1; break; } pt = (s->buffer[i+5] & 0x1c) >> 3; temp_ref = (s->buffer[i+4]<<2)+(s->buffer[i+5]>>6); break; } if(err) break; //something went wrong if(s->buffer[i+3] >= 0x01 && s->buffer[i+3] <= 0xAF) break; //slice, we have already analized what we need } i++; } if(err) mp_msg(MSGT_MUXER, MSGL_ERR,"Warning: picture too short or broken!\n"); //following 2 lines are workaround: lavf doesn't sync to sequence headers before passing demux_packets if(!spriv->nom_delta_pts) spriv->delta_pts = spriv->nom_delta_pts = parse_fps(fps); if(!spriv->vframes) spriv->last_tr = spriv->max_tr = temp_ref; d1 = temp_ref - spriv->last_tr; if(gop_reset) frames_diff = spriv->max_tr + 1 + temp_ref - spriv->last_tr; else { if(d1 < -6) //there's a wraparound frames_diff = spriv->max_tr + 1 + temp_ref - spriv->last_tr; else if(d1 > 6) //there's a wraparound frames_diff = spriv->max_tr + 1 + spriv->last_tr - temp_ref; else if(!d1) //pre-emptive fix against broken sequences frames_diff = 1; else frames_diff = d1; } mp_msg(MSGT_MUXER, MSGL_DBG2, "\nLAST: %d, TR: %d, GOP: %d, DIFF: %d, MAX: %d, d1: %d\n", spriv->last_tr, temp_ref, gop_reset, frames_diff, spriv->max_tr, d1); if(temp_ref > spriv->max_tr || gop_reset) spriv->max_tr = temp_ref; spriv->last_tr = temp_ref; if(spriv->picture.mpeg1 == 0) { if(spriv->telecine && pce_ptr) { soft_telecine(priv, spriv, fps_ptr, se_ptr, pce_ptr, frames_diff); spriv->picture.display_time = 100; mp_header_process_extension(&(spriv->picture), pce_ptr); if(spriv->picture.display_time >= 50 && spriv->picture.display_time <= 300) spriv->delta_pts = (spriv->nom_delta_pts * spriv->picture.display_time) / 100; } } if(! spriv->vframes) frames_diff = 1; spriv->last_dts += spriv->delta_pts; spriv->last_pts += spriv->nom_delta_pts*(frames_diff-1) + spriv->delta_pts; ret = add_frame(spriv, spriv->delta_pts, s->buffer, len, pt, spriv->last_dts, spriv->last_pts); if(ret < 0) { mp_msg(MSGT_MUXER, MSGL_FATAL, "\r\nPARSE_MPEG12: add_frames(%d) failed, exit\r\n", len); return 0; } mp_msg(MSGT_MUXER, MSGL_DBG2, "\r\nVIDEO FRAME, PT: %C, tr: %d, diff: %d, dts: %.3lf, pts: %.3lf, pdt: %u, gop_reset: %d\r\n", ftypes[pt], temp_ref, frames_diff, ((double) spriv->last_dts/27000000.0f), ((double) spriv->last_pts/27000000.0f), spriv->picture.display_time, gop_reset); if(pt == B_FRAME) { int j, n, adj = 0; int64_t diff = spriv->last_dts - spriv->last_pts; if(diff != 0) { n = spriv->framebuf_used - 1; for(j = n; j >= 0; j--) { if(spriv->framebuf[j].pts >= spriv->last_pts) { spriv->framebuf[j].pts += diff; adj++; } } mp_msg(MSGT_MUXER, MSGL_V, "\r\nResynced B-frame by %d units, DIFF: %"PRId64" (%.3lf),[pd]ts=%.3lf\r\n", n, diff, (double) diff/27000000.0f, (double) spriv->last_pts/27000000.0f); spriv->last_pts = spriv->last_dts; } } spriv->vframes++; mp_msg(MSGT_MUXER, MSGL_DBG2,"parse_mpeg12_video, return %u\n", (uint32_t) len); return len;}static uint64_t fix_mp4_frame_duration(muxer_headers_t *vpriv){ uint64_t mn, md, mx, diff; uint32_t i; mn = mx = vpriv->framebuf[0].pts; for(i = 0; i < 3; i++) { mp_msg(MSGT_DECVIDEO,MSGL_DBG2, "PTS: %"PRIu64"\n", vpriv->framebuf[i].pts); if(vpriv->framebuf[i].pts < mn) mn = vpriv->framebuf[i].pts; if(vpriv->framebuf[i].pts > mx) mx = vpriv->framebuf[i].pts; } md = mn; for(i=0; i<3; i++) { if((vpriv->framebuf[i].pts > mn) && (vpriv->framebuf[i].pts < mx)) md = vpriv->framebuf[i].pts; } if(mx - md > md - mn) diff = md - mn; else diff = mx - md; mp_msg(MSGT_DECVIDEO,MSGL_DBG2, "MIN: %"PRIu64", mid: %"PRIu64", max: %"PRIu64", diff: %"PRIu64"\n", mn, md, mx, diff); if(diff > 0) { for(i=0; i<3; i++) { vpriv->framebuf[i].pts += diff; vpriv->framebuf[i].dts += i * diff; mp_msg(MSGT_MUXER, MSGL_DBG2, "FIXED_PTS: %.3lf, FIXED_DTS: %.3lf\n", (double) (vpriv->framebuf[i].pts/27000000.0), (double) (vpriv->framebuf[i].dts/27000000.0)); } return diff; } else return 0;}static size_t parse_mpeg4_video(muxer_stream_t *s, muxer_priv_t *priv, muxer_headers_t *vpriv, float fps, size_t len){ size_t ptr = 0; int64_t delta_pts=0; uint8_t pt; int ret; mp_msg(MSGT_MUXER, MSGL_DBG2,"parse_mpeg4_video, len=%u\n", (uint32_t) len); if(len<6) { mp_msg(MSGT_MUXER, MSGL_ERR,"Frame too short: %d, exit!\n", len); return 0; } pt = 0; while(ptr < len - 5) { if(s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || s->buffer[ptr+2] != 1) { ptr++; continue; } if(s->buffer[ptr+3] >= 0x20 && s->buffer[ptr+3] <= 0x2f) //VOL { mp4_header_process_vol(&(vpriv->picture), &(s->buffer[ptr+4])); } else if(s->buffer[ptr+3] == 0xb3) //gov { //fprintf(stderr, "\nGOV\n"); } else if(s->buffer[ptr+3] == 0xb6) //vop { int32_t delta; mp4_header_process_vop(&(vpriv->picture), &(s->buffer[ptr+4])); delta = vpriv->picture.timeinc_unit - vpriv->last_tr; if((delta > 0) && (delta > (vpriv->picture.timeinc_resolution/2))) delta -= vpriv->picture.timeinc_resolution; else if((delta < 0) && (delta < (-(vpriv->picture.timeinc_resolution/2)))) delta += vpriv->picture.timeinc_resolution; delta_pts = (27000000 * (int64_t) delta) / vpriv->picture.timeinc_resolution; //warning, it seems that packed bops can lead to delta == 0 pt = vpriv->picture.picture_type + 1; mp_msg(MSGT_MUXER, MSGL_DBG2, "\nTYPE: %c, RESOLUTION: %d, TEMP: %d, delta: %d, delta_pts: %"PRId64" = %.3lf, delta2: %.3lf\n", FTYPE(pt), vpriv->picture.timeinc_resolution, vpriv->picture.timeinc_unit, delta, delta_pts, (double) (delta_pts/27000000.0), (double) delta / (double) vpriv->picture.timeinc_resolution); vpriv->last_tr = vpriv->picture.timeinc_unit; break; } ptr++; } if(vpriv->vframes) { vpriv->last_dts += vpriv->frame_duration; vpriv->last_pts += delta_pts; } ret = add_frame(vpriv, delta_pts, s->buffer, len, pt, vpriv->last_dts, vpriv->last_pts); if(ret < 0) { mp_msg(MSGT_MUXER, MSGL_FATAL, "\r\nPARSE_MPEG4: add_frames(%d) failed, exit\r\n", len); return 0; } if(!vpriv->frame_duration && vpriv->framebuf_used == 3) { vpriv->frame_duration = fix_mp4_frame_duration(vpriv); if(vpriv->frame_duration) { vpriv->last_pts += vpriv->frame_duration; vpriv->last_dts = vpriv->framebuf[vpriv->framebuf_used-1].dts; vpriv->delta_clock = ((double) vpriv->frame_duration)/27000000.0; mp_msg(MSGT_MUXER, MSGL_INFO, "FRAME DURATION: %"PRIu64" %.3lf\n", vpriv->frame_duration, (double) (vpriv->frame_duration/27000000.0)); vpriv->is_ready = 1; } } mp_msg(MSGT_MUXER, MSGL_DBG2, "LAST_PTS: %.3lf, LAST_DTS: %.3lf\n", (double) (vpriv->last_pts/27000000.0), (double) (vpriv->last_dts/27000000.0)); vpriv->vframes++; return len;}static int fill_last_frame(muxer_headers_t *spriv, uint8_t *ptr, int len){ int idx; if(!len) return 0; if(spriv->framebuf_used == 0) idx = spriv->framebuf_used; else idx = spriv->framebuf_used - 1; if(spriv->framebuf[idx].alloc_size < spriv->framebuf[idx].size + len) { if(spriv->framebuf[idx].size > SIZE_MAX - (size_t)len) return 0; spriv->framebuf[idx].buffer = (uint8_t*) realloc(spriv->framebuf[idx].buffer, spriv->framebuf[idx].size + len); if(! spriv->framebuf[idx].buffer) return 0; spriv->framebuf[idx].alloc_size = spriv->framebuf[idx].size + len; } memcpy(&(spriv->framebuf[idx].buffer[spriv->framebuf[idx].size]), ptr, len); spriv->framebuf[idx].size += len; return len;}static int add_frame(muxer_headers_t *spriv, uint64_t idur, uint8_t *ptr, int len, uint8_t pt, uint64_t dts, uint64_t pts){ int idx; idx = spriv->framebuf_used; if(idx >= spriv->framebuf_cnt) { spriv->framebuf = (mpeg_frame_t*) realloc_struct(spriv->framebuf, (spriv->framebuf_cnt+1), sizeof(mpeg_frame_t)); if(spriv->framebuf == NULL) { mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(idx), abort\n"); return -1; } spriv->framebuf[spriv->framebuf_cnt].size = 0; spriv->framebuf[spriv->framebuf_cnt].alloc_size = 0; spriv->framebuf[spriv->framebuf_cnt].pos = 0; spriv->framebuf[spriv->framebuf_cnt].buffer = (uint8_t*) malloc(len); if(spriv->framebuf[spriv->framebuf_cnt].buffer == NULL) { mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(frame), abort\n"); return -1; } spriv->framebuf[spriv->framebuf_cnt].alloc_size = len; spriv->framebuf_cnt++; } if(spriv->framebuf[idx].alloc_size < spriv->framebuf[idx].size + len) { if(spriv->framebuf[idx].size > SIZE_MAX - (size_t)len) { mp_msg(MSGT_MUXER, MSGL_FATAL, "Size overflow, couldn't realloc frame buffer(frame), abort\n"); return -1; } spriv->framebuf[idx].buffer = realloc(spriv->framebuf[idx].buffer, spriv->framebuf[idx].size + len);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?