📄 muxer_mpeg.c
字号:
if(spriv->picture.mpeg1 == 0 && priv->patch_sde) { while((s->buffer[tmp] != 0 || s->buffer[tmp+1] != 0 || s->buffer[tmp+2] != 1 || s->buffer[tmp+3] != 0xb5 || ((s->buffer[tmp+4] & 0xf0) != 0x20)) && (tmp < len-5)) tmp++; if(tmp < len-5) //found patch_panscan(priv, &(s->buffer[tmp+4])); } if(s->buffer[3]) { // Sequence or GOP -- scan for Picture s->gop_start = s->h.dwLength; while (ptr < len-5 && (s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || s->buffer[ptr+2] != 1 || s->buffer[ptr+3] != 0)) ptr++; } if (ptr >= len-5) { pt = 0; // Picture not found?! temp_ref = 0; mp_msg(MSGT_MUXER, MSGL_ERR,"Warning: picture not found in GOP!\n"); } else { pt = (s->buffer[ptr+5] & 0x1c) >> 3; temp_ref = (s->buffer[ptr+4]<<2)+(s->buffer[ptr+5]>>6); if(!spriv->vframes) spriv->last_tr = spriv->max_tr = temp_ref; d1 = temp_ref - spriv->last_tr; 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 frames_diff = d1; mp_msg(MSGT_MUXER, MSGL_V, "\nLAST: %d, TR: %d, DIFF: %d, MAX: %d, d1: %d\n", spriv->last_tr, temp_ref, frames_diff, spriv->max_tr, d1); if(!temp_ref) spriv->max_tr = 0; else if(temp_ref > spriv->max_tr) spriv->max_tr = temp_ref; spriv->last_tr = temp_ref; mp_msg(MSGT_MUXER, MSGL_V, "Video frame type: %c, TR: %d\n", FTYPE(pt), temp_ref); if(spriv->picture.mpeg1 == 0) { size_t tmp = ptr; while (ptr < len-5 && (s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || s->buffer[ptr+2] != 1 || s->buffer[ptr+3] != 0xb5)) ptr++; if(ptr < len-5) { pce_ptr = &(s->buffer[ptr+4]); if(spriv->telecine) soft_telecine(spriv, fps_ptr, se_ptr, pce_ptr, frames_diff); mp_header_process_extension(&(spriv->picture), &(s->buffer[ptr+4])); if(spriv->picture.display_time >= 50 && spriv->picture.display_time <= 300) spriv->delta_pts = (spriv->nom_delta_pts * spriv->picture.display_time) / 100; } else spriv->delta_pts = spriv->nom_delta_pts; ptr = tmp; } } switch (pt) { case 2: // predictive if (s->ipb[0]) { sz = len + s->ipb[0]; s->ipb[0] = max(s->ipb[0], s->ipb[2]); s->ipb[2] = 0; } else if (s->ipb[2]) { sz = len + s->ipb[2]; s->ipb[0] = s->ipb[2]; s->ipb[2] = 0; } else sz = 4 * len; // no bidirectional frames yet? s->ipb[1] = len; break; case 3: // bidirectional s->ipb[2] += len; sz = s->ipb[1] + s->ipb[2]; break; default: // intra-coded sz = len; // no extra buffer for it... } spriv->vframes++; reorder_frame(spriv, s->buffer, len, pt, temp_ref, spriv->delta_pts); } mp_msg(MSGT_MUXER, MSGL_V,"parse_mpeg12_video, return %u\n", (uint32_t) len); return sz;}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_V, "PTS: %llu\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; } mp_msg(MSGT_DECVIDEO,MSGL_V, "MIN: %llu, mid: %llu, max: %llu\n", mn, md, mx); if(mx - md > md - mn) diff = md - mn; else diff = mx - md; 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_V, "FIXED_PTS: %.3lf, FIXED_DTS: %.3lf\n", (double) (vpriv->framebuf[i].pts/92160000.0), (double) (vpriv->framebuf[i].dts/92160000.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; uint8_t pt; mp_msg(MSGT_MUXER, MSGL_V,"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; } 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 = (92160000 * (int64_t) delta) / vpriv->picture.timeinc_resolution; pt = vpriv->picture.picture_type + 1; mp_msg(MSGT_MUXER, MSGL_V, "\nTYPE: %c, RESOLUTION: %d, TEMP: %d, delta: %d, delta_pts: %lld = %.3lf, delta2: %.3lf\n", FTYPE(pt), vpriv->picture.timeinc_resolution, vpriv->picture.timeinc_unit, delta, delta_pts, (double) (delta_pts/92160000.0), (double) delta / (double) vpriv->picture.timeinc_resolution); vpriv->last_tr = vpriv->picture.timeinc_unit; break; } ptr++; } vpriv->last_dts += vpriv->frame_duration; vpriv->last_pts += delta_pts; reorder_frame(vpriv, s->buffer, len, pt, 0, delta_pts); vpriv->framebuf[vpriv->framebuf_used-1].pts = vpriv->last_pts; vpriv->framebuf[vpriv->framebuf_used-1].dts = vpriv->last_dts; vpriv->framebuf[vpriv->framebuf_used-1].idur = vpriv->frame_duration; /*mp_msg(MSGT_MUXER, MSGL_V, "\nMPEG4V, PT: %c, LEN=%u, DELTA_PTS: %.3lf, PTS: %.3lf, DTS: %.3lf\n", FTYPE(pt), len, (delta_pts/92160000.0), (double) (vpriv->framebuf[vpriv->framebuf_used-1].pts/92160000.0), (double) (vpriv->framebuf[vpriv->framebuf_used-1].dts/92160000.0), len);*/ 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)/92160000.0; mp_msg(MSGT_MUXER, MSGL_INFO, "FRAME DURATION: %llu %.3lf\n", vpriv->frame_duration, (double) (vpriv->frame_duration/92160000.0)); } } mp_msg(MSGT_MUXER, MSGL_V, "LAST_PTS: %.3lf, LAST_DTS: %.3lf\n", (double) (vpriv->last_pts/92160000.0), (double) (vpriv->last_dts/92160000.0)); return len;}static void mpegfile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags){ size_t ptr=0, sz = 0; uint64_t pts, tmp; muxer_t *muxer = s->muxer; muxer_priv_t *priv = (muxer_priv_t *)muxer->priv; muxer_headers_t *spriv = (muxer_headers_t*) s->priv; FILE *f; float fps; uint32_t stream_format; f = muxer->file; if(s->buffer == NULL) return; pts = 0; if (s->type == MUXER_TYPE_VIDEO) { // try to recognize frame type... fps = (float) s->h.dwRate/ (float) s->h.dwScale; spriv->type = 1; spriv->has_pes_priv_headers = 0; stream_format = s->bih->biCompression; if(is_mpeg1(stream_format) || is_mpeg2(stream_format)) { spriv->is_mpeg12 = 1; if(len) sz = parse_mpeg12_video(s, priv, spriv, fps, len); else { tmp = (uint64_t) (92160000 / fps); spriv->last_pts += tmp; spriv->last_dts += tmp; } } else if(is_mpeg4(stream_format)) { spriv->is_mpeg12 = 0; spriv->reorder = 0; spriv->telecine = 0; if(spriv->size == 0) priv->use_psm = 1; if(len) sz = parse_mpeg4_video(s, priv, spriv, fps, len); else { tmp = (uint64_t) (92160000 / fps); spriv->last_pts += tmp; spriv->last_dts += tmp; } } mp_msg(MSGT_MUXER, MSGL_V,"mpegfile_write_chunk, Video codec=%x, len=%u, mpeg12 returned %u\n", stream_format, (uint32_t) len, (uint32_t) sz); ptr = 0; priv->vbytes += len; sz <<= 1; } else { // MUXER_TYPE_AUDIO spriv->type = 0; stream_format = s->wf->wFormatTag; mp_msg(MSGT_MUXER, MSGL_V,"\nmpegfile_write_chunk, Audio codec=%x, len=%u, frame size=%u\n", stream_format, (uint32_t) len, (uint32_t) spriv->frame_size); if(spriv->bitrate == 0) spriv->bitrate = s->wf->nAvgBytesPerSec; // I need to know the audio frame size if(spriv->frame_size == 0) { spriv->frame_size = get_audio_frame_size(spriv, s->buffer, stream_format, s->wf->nSamplesPerSec); spriv->aframe_delta_pts = ((double) spriv->frame_size / (double) spriv->bitrate); //spriv->delta_pts = (uint64_t) (spriv->aframe_delta_pts * 92160000); spriv->delta_pts = (uint64_t) (92160000 * spriv->frame_size) / spriv->bitrate; mp_msg(MSGT_MUXER, MSGL_INFO, "AUDIO FRAME SIZE: %u, DELTA_PTS: %llu (%.3lf)\n", (uint32_t) spriv->frame_size, spriv->delta_pts, spriv->aframe_delta_pts); } if(s->b_buffer_size - s->b_buffer_len < len) { s->b_buffer = realloc(s->b_buffer, len + s->b_buffer_len); if(s->b_buffer == NULL) { mp_msg(MSGT_MUXER, MSGL_FATAL, "\nFATAL! couldn't realloc %d bytes\n", len + s->b_buffer_len); return; } s->b_buffer_size = len + s->b_buffer_len; mp_msg(MSGT_MUXER, MSGL_DBG2, "REALLOC(%d) bytes to AUDIO backbuffer\n", s->b_buffer_size); } memcpy(&(s->b_buffer[s->b_buffer_ptr + s->b_buffer_len]), s->buffer, len); s->b_buffer_len += len; if(stream_format == AUDIO_A52) { s->type = 1; s->ckid = be2me_32 (0x1bd); if(s->size == 0) { spriv->max_pl_size -= 4; if(priv->is_genmpeg1 || priv->is_genmpeg2) fix_audio_sys_header(priv, spriv->id, 0xbd, 58*1024); //only one audio at the moment spriv->id = 0xbd; } } if(priv->init_adelay < 0) { uint64_t delay_len; priv->abytes += len; delay_len = (uint64_t) abs((priv->init_adelay * (double) spriv->bitrate)); if(priv->abytes >= delay_len) { if(priv->drop) { mp_msg(MSGT_MUXER, MSGL_V, "\nDROPPING %llu AUDIO BYTES, DELAY: %.3lf, BR: %u\n", delay_len, priv->init_adelay, spriv->bitrate); drop_delayed_audio(muxer, s, (int64_t) delay_len); } else { mp_msg(MSGT_MUXER, MSGL_V, "\nWRITING %llu EARLY AUDIO BYTES, DELAY: %.3lf, BR: %u\n", delay_len, priv->init_adelay, spriv->bitrate); save_delayed_audio(muxer, s, (uint64_t) (92160000 * (-priv->init_adelay))); } priv->init_adelay = 0.0; conf_init_adelay = 0; priv->drop = 0; } } sz = max(len, 2 * priv->packet_size); } if (s->h.dwSampleSize) { // CBR s->h.dwLength += len/s->h.dwSampleSize; if (len%s->h.dwSampleSize) mp_msg(MSGT_MUXER, MSGL_ERR, "Warning! len isn't divisable by samplesize!\n"); } else { // VBR s->h.dwLength++; } s->size += len; s->timer = (double)s->h.dwLength*s->h.dwScale/s->h.dwRate; //if genmpeg1/2 and sz > last buffer size in the system header we must write the new sysheader if(sz > s->h.dwSuggestedBufferSize) { // increase and set STD s->h.dwSuggestedBufferSize = sz; if(priv->is_genmpeg1 || priv->is_genmpeg2) { fix_buffer_params(priv, spriv->id, s->h.dwSuggestedBufferSize); priv->update_system_header = 1; } } if(spriv->psm_fixed == 0) { add_to_psm(priv, spriv->id, stream_format); spriv->psm_fixed = 1; priv->psm_streams_cnt++; if((priv->psm_streams_cnt == muxer->num_videos + muxer->num_audios) && priv->use_psm) write_psm_block(muxer, muxer->file); } if(priv->init_adelay != 0) return; flush_buffers(muxer, 0);}static void mpegfile_write_index(muxer_t *muxer){ muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; while(flush_buffers(muxer, 0) > 0); flush_buffers(muxer, 1); if(priv->is_genmpeg1 || priv->is_genmpeg2) write_mpeg_pack(muxer, NULL, muxer->file, NULL, 0, 1); //insert fake Nav Packet mp_msg(MSGT_MUXER, MSGL_INFO, "\nOverhead: %.3lf%% (%llu / %llu)\n", 100.0 * (double)priv->headers_size / (double)priv->data_size, priv->headers_size, priv->data_size);}static void mpegfile_write_header(muxer_t *muxer){ muxer_priv_t *priv = (muxer_priv_t*) muxer->priv; priv->headers_cnt++; if((priv->is_genmpeg1 || priv->is_genmpeg2) && (priv->headers_cnt == muxer->avih.dwStreams)) { int i; for(i = 0; i < muxer->avih.dwStreams; i++) { priv->sys_info.streams[i].bufsize = muxer->streams[i]->h.dwSuggestedBufferSize; mp_msg(MSGT_MUXER, MSGL_V, "IDX: %d, BUFSIZE: %u\n", i, priv->sys_info.streams[i].bufsize); } } //write the first system header only for generic mpeg1/2 muxes, and only when we have collected all necessary infos if(priv->is_genmpeg1 || priv->is_genmpeg2 || ((priv->is_xvcd || priv->is_xsvcd) && (priv->headers_cnt == 1))) { write_mpeg_pack(muxer, NULL, muxer->file, NULL, 0, 0); priv->update_system_header = 0; } return;}static void setup_sys_params(muxer_priv_t *priv){ if(priv->is_dvd) { priv->sys_info.cnt = 4; priv->sys_info.streams[0].id = 0xb9; priv->sys_info.streams[0].type = 1; priv->sys_info.streams[0].bufsize = 232*1024; priv->sys_info.streams[1].id = 0xb8; priv->sys_info.streams[1].type = 0; priv->sys_info.streams[1].bufsize = 4*1024; priv->sys_info.streams[2].id = 0xbd; priv->sys_info.streams[2].type = 1; priv->sys_info.streams[2].bufsize = 58*1024; priv->sys_info.streams[3].id = 0xbf; priv->sys_info.streams[3].type = 1; priv->sys_info.streams[3].bufsize = 2*1024; } else if(priv->is_xvcd || priv->is_xsvcd) { priv->sys_info.cnt = 2; priv->sys_info.streams[0].id = 0xe0; priv->sys_info.streams[0].type = 1; priv->sys_info.streams[0].bufsize = (priv->is_xvcd ? 46: 230)*1024; priv->sys_info.streams[1].id = 0xc0; priv->sys_info.streams[1].type = 0; priv->sys_info.streams[1].bufsize = 4*1024; } else priv->sys_info.cnt = 0;}int muxer_init_muxer_mpeg(muxer_t *muxer){ muxer_priv_t *priv; priv = (muxer_priv_t *) calloc(1, sizeof(muxer_pri
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -