/* * demuxer.c * * Copyright (C) Thomas Oestreich - June 2001 * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "transcode.h" #include "libtc/libtc.h" #include "tcinfo.h" #include "ioaux.h" #include "aux_pes.h" #include "seqinfo.h" #include "demuxer.h" #include "packets.h" #include static int demux_mode=TC_DEMUX_SEQ_ADJUST; int gop, gop_pts, gop_cnt; typedef struct timecode_struc /* Time_code Struktur laut MPEG */ { unsigned long msb; /* fuer SCR, DTS, PTS */ unsigned long lsb; unsigned long reference_ext; unsigned long negative; /* for delays when doing multiple files */ } Timecode_struc; #define MAX_FFFFFFFF 4294967295.0 /* = 0xffffffff in hex. */ /* ------------------------------------------------------------ * * support code (scr_rewrite()) moved from aux_pes.c * * ------------------------------------------------------------*/ static void make_timecode (double timestamp, Timecode_struc *pointer) { double temp_ts; if (timestamp < 0.0) { pointer->negative = 1; timestamp = -timestamp; } else pointer->negative = 0; temp_ts = floor(timestamp / 300.0); if (temp_ts > MAX_FFFFFFFF) { pointer->msb=1; temp_ts -= MAX_FFFFFFFF; pointer->lsb=(unsigned long)temp_ts; } else { pointer->msb=0; pointer->lsb=(unsigned long)temp_ts; } pointer->reference_ext = (unsigned long)(timestamp - (floor(timestamp / 300.0) * 300.0)); } #define MPEG2_MARKER_SCR 1 /* MPEG2 Marker SCR */ /************************************************************************* Kopiert einen TimeCode in einen Bytebuffer. Dabei wird er nach MPEG-Verfahren in bits aufgesplittet. Makes a Copy of a TimeCode in a Buffer, splitting it into bitfields according to MPEG-System *************************************************************************/ static void buffer_timecode_scr (Timecode_struc *pointer, unsigned char **buffer) { unsigned char temp; unsigned char marker=MPEG2_MARKER_SCR; temp = (marker << 6) | (pointer->msb << 5) | ((pointer->lsb >> 27) & 0x18) | 0x4 | ((pointer->lsb >> 28) & 0x3); *((*buffer)++)=temp; temp = (pointer->lsb & 0x0ff00000) >> 20; *((*buffer)++)=temp; temp = ((pointer->lsb & 0x000f8000) >> 12) | 0x4 | ((pointer->lsb & 0x00006000) >> 13); *((*buffer)++)=temp; temp = (pointer->lsb & 0x00001fe0) >> 5; *((*buffer)++)=temp; temp = ((pointer->lsb & 0x0000001f) << 3) | 0x4 | ((pointer->reference_ext & 0x00000180) >> 7); *((*buffer)++)=temp; temp = ((pointer->reference_ext & 0x0000007F) << 1) | 1; *((*buffer)++)=temp; } static void scr_rewrite(char *buf, uint32_t pts) { Timecode_struc timecode; unsigned char * ucbuf = (unsigned char *)buf; timecode.msb = 0; timecode.lsb = 0; timecode.reference_ext = 0; timecode.negative = 0; make_timecode((double) pts, &timecode); buffer_timecode_scr(&timecode, &ucbuf); } /* ------------------------------------------------------------ * * demuxer / synchronization thread * * ------------------------------------------------------------*/ void tcdemux_thread(info_t *ipipe) { int k, id=0, zz=0; int j, i, bytes, filesize; char *buffer=NULL; int payload_id=0, select=PACKAGE_ALL; double pts=0.0f, ref_pts=0.0f, resync_pts=-1.0f, pts_diff=0.0f, track_initial_pts=0.0f; double av_fine_pts1=-1.0f, av_fine_pts2=-1.0f, av_fine_diff=0.0f; uint32_t frame_based_lpts=0; int unit_seek=0, unit, track=0, is_track=0; int resync_seq1=0, resync_seq2=INT_MAX, seq_dump, seq_seek; int keep_seq = 0; int hard_fps = 0; int has_pts_dts=0, demux_video=0, demux_audio=0; int flag_flush = 0; int flag_force = 0; int flag_eos = 0; int flag_has_audio = 0; int flag_append_audio = 0; int flag_notify = 1; int flag_avsync = 1; int flag_skip = 0; int flag_sync_reset = 0; int flag_sync_active = 0; int flag_loop_all = 0; int flag_av_fine_tune = 0; int flag_rewrite_scr = 0; int flag_field_encoded= 0; //for demux_mode=2 int seq_picture_ctr=0, pack_picture_ctr=0, sequence_ctr=0, packet_ctr=0; char buf[256]; const char *logfile; unsigned long i_pts, i_dts; unsigned int packet_size=VOB_PACKET_SIZE; seq_list_t *ptr=NULL; double fps; // allocate space if((buffer = tc_zalloc(packet_size))==NULL) { tc_log_perror(__FILE__, "out of memory"); exit(1); } // copy info parameter to local variables unit_seek = ipipe->ps_unit; resync_seq1 = ipipe->ps_seq1; resync_seq2 = ipipe->ps_seq2; track = ipipe->track; //map track on substream id switch(ipipe->codec) { case TC_CODEC_SUB: track+=0x20; flag_rewrite_scr=1; break; case TC_CODEC_AC3: track+=0x80; break; case TC_CODEC_PCM: track+=0xA0; break; case TC_CODEC_MP3: track+=0xC0; break; case TC_CODEC_MPEG2: // for MPEG2 video, use this substream id for sync adjustment track=ipipe->subid; demux_video=1; break; } //0.6.0pre4 if(demux_video==0) { if(ipipe->demux == TC_DEMUX_SEQ_FSYNC) ipipe->demux=TC_DEMUX_SEQ_ADJUST; if(ipipe->demux == TC_DEMUX_SEQ_FSYNC2) ipipe->demux=TC_DEMUX_SEQ_ADJUST2; //substream synchonized with video in "force frame rate" mode demux_audio=1; } if(ipipe->demux == TC_DEMUX_SEQ_FSYNC || ipipe->demux == TC_DEMUX_SEQ_FSYNC2 || ipipe->demux == TC_DEMUX_SEQ_LIST) { //allocate buffer if(flush_buffer_init(ipipe->fd_out, ipipe->verbose)<0) { tc_log_error(__FILE__, "flush buffer facility init failed"); exit(1); } //need to open the logfile if(seq_init(ipipe->name, ipipe->fd_log, ipipe->fps, ipipe->verbose)<0) { tc_log_error(__FILE__, "sync mode init failed"); exit(1); } } //new default behaving: // if(unit_seek==0 && resync_seq1==0 && resync_seq2 == INT_MAX) flag_loop_all=1; //changes 0.6.0pre3: //tcprobe selects start unit --> switch to flag_loop_all always true // for any given unit if(resync_seq1==0 && resync_seq2 == INT_MAX) flag_loop_all=1; demux_mode = ipipe->demux; select = ipipe->select; fps = ipipe->fps; logfile = ipipe->name; keep_seq = ipipe->keep_seq; hard_fps = ipipe->hard_fps_flag; j=0; //packet counter i=0; //skipped packets counter k=0; //unit counter // will be switched on as soon start of sequences to flush is reached flag_flush=0; flag_notify=1; flag_avsync=0; flag_append_audio=0; if(keep_seq) flag_sync_active=1; unit=unit_seek; seq_seek = resync_seq1; seq_dump = resync_seq2 - resync_seq1; ++unit_seek; ++seq_seek; if(!flag_loop_all) { tc_log_msg(__FILE__, "seeking to sequence %d:%d ...", unit, resync_seq1); } filesize = 0; for(;;) { /* ------------------------------------------------------------ * * (I) read a 2048k block * * ------------------------------------------------------------*/ if((bytes=tc_pread(ipipe->fd_in, buffer, packet_size)) != packet_size) { //program end code? if(bytes==4) { if(scan_pack_header(buffer, MPEG_PROGRAM_END_CODE)) { if(ipipe->verbose & TC_DEBUG) tc_log_msg(__FILE__, "(pid=%d) program stream end code detected", getpid()); break; } } if(bytes) tc_log_warn(__FILE__, "invalid program stream packet size (%d/%d)", bytes, packet_size); break; } filesize += bytes; // do not make any tests in pass-through mode if(demux_mode==TC_DEMUX_OFF) goto flush_packet; /* ------------------------------------------------------------ * * (II) packet header ok? * * ------------------------------------------------------------*/ if(!scan_pack_header(buffer, TC_MAGIC_VOB)) { if(flag_notify && (ipipe->verbose & TC_DEBUG)) tc_log_warn(__FILE__, "(pid=%d) invalid packet header detected", getpid()); // something else? if(scan_pack_header(buffer, MPEG_VIDEO) | scan_pack_header(buffer, MPEG_AUDIO)) { if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "(pid=%d) MPEG system stream detected", getpid()); if(scan_pack_header(buffer, MPEG_VIDEO)) payload_id=PACKAGE_VIDEO; if(scan_pack_header(buffer, MPEG_AUDIO)) payload_id=PACKAGE_AUDIO_MP3; // no further processing goto flush_packet; } else { tc_log_warn(__FILE__, "(pid=%d) '0x%02x%02x%02x%02x' not yet supported", getpid(), buffer[0] & 0xff, buffer[1] & 0xff, buffer[2] & 0xff, buffer[3] & 0xff); break; } } else { //MPEG1? if ((buffer[4] & 0xf0) == 0x20) { payload_id=PACKAGE_MPEG1; flag_flush=1; if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "(pid=%d) MPEG-1 video stream detected", getpid()); // no further processing goto flush_packet; } } /* ------------------------------------------------------------ * * (III) analyze packet contents * * ------------------------------------------------------------*/ // proceed with a valid package, assume defaults flag_skip=0; //do not skip has_pts_dts=0; //no pts_dts stamp payload_id=0; //payload unknown flag_sync_reset=0; //no reset of syncinfo id = buffer[17] & 0xff; //payload id byte //MPEG 2? if ((buffer[4] & 0xc0) == 0x40) { // do not change any flags if(ipipe->verbose & TC_STATS) { //display info only once tc_log_msg(__FILE__, "(pid=%d) MPEG-2 video stream detected", getpid()); } } else { //MPEG1 if ((buffer[4] & 0xf0) == 0x20) { payload_id=PACKAGE_MPEG1; if(ipipe->verbose & TC_STATS) { //display info only once tc_log_msg(__FILE__, "(pid=%d) MPEG-1 video stream detected", getpid()); } } else { payload_id=PACKAGE_PASS; if(ipipe->verbose & TC_DEBUG) tc_log_warn(__FILE__, "(pid=%d) unknown stream packet id detected", getpid()); } //flush all MPEG1 stuff goto flush_packet; } /* ------------------------------------------------------------ * * (IV) audio payload * * ------------------------------------------------------------*/ // check payload id // process this audio packet? // sync to AC3 audio mode? if(id == P_ID_AC3) payload_id = PACKAGE_PRIVATE_STREAM; // sync to MP3 audio mode? if(id >= 0xc0 && id <= 0xdf) payload_id = PACKAGE_AUDIO_MP3; // are we dealing with the right track? // check here: is_track=0; if(payload_id == PACKAGE_PRIVATE_STREAM) { //position of track code uint8_t *_buf=buffer+14; uint8_t *_tmp=_buf + 9 + _buf[8]; is_track = ((*_tmp) == track) ? 1:0; if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "substream [0x%x] %d", *_tmp, is_track); if(is_track==0) { flag_skip=1; //drop this packet } else { flag_skip=0; goto sync_track; } } if(payload_id & PACKAGE_AUDIO_MP3) { is_track = ((id) == track) ? 1:0; if(is_track==0) flag_skip=1; //drop this packet if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "MPEG audio track [0x%x] %d", id, is_track); } sync_track: if(is_track) { if(flag_sync_active==0) { //first valid audio packet! // get pts time stamp: ac_memcpy(buf, &buffer[20], 16); has_pts_dts=get_pts_dts(buf, &i_pts, &i_dts); if(has_pts_dts) { track_initial_pts=(double)i_pts/90000.; } else { //fallback to scr time stamp: ac_memcpy(buf, &buffer[4], 6); track_initial_pts = read_time_stamp(buf); } if(resync_pts<0) { pts_diff = track_initial_pts; } else { pts_diff = track_initial_pts - resync_pts; } //pts_diff<0 is OK, the packets will be dropped to establish sync //pts_diff>0 is not so simple, since we need to drop video //packets, already submitted to flush buffer //enable sync mode, check for PTS giant leap???? if(pts_diff < TC_DEMUX_MIN_PTS || pts_diff > TC_DEMUX_CRIT_PTS) flag_sync_active = 1; //0.6.0pre5: frame dropping handled by transcode flag_sync_active=1; //unless this flag is on, the video sequence is dropped //in TC_DEMUX_SEQ_FSYNC mode } // sync now, if requested: if(!unit_seek) flag_has_audio=1; //unit has audio packets // need to find the time difference of two audio packets // for fine-tuning AV sync. if(flag_av_fine_tune == 0) { // get pts time stamp: ac_memcpy(buf, &buffer[20], 16); has_pts_dts=get_pts_dts(buf, &i_pts, &i_dts); if(av_fine_pts1<0) { av_fine_pts1 = (double)i_pts/90000.; } else { av_fine_pts2 = (double)i_pts/90000.; flag_av_fine_tune=1; } //diff: if(flag_av_fine_tune==1) { av_fine_diff=av_fine_pts2-av_fine_pts1; if(ipipe->verbose & TC_DEBUG) tc_log_msg(__FILE__, "AV fine-tuning: %d ms", (int)(av_fine_diff*1000)); } //sanity check: if(av_fine_diff<0) av_fine_diff=0.0f; } //Pre-processing: check if we need to re-sync? if(demux_mode == TC_DEMUX_SEQ_FSYNC2 || demux_mode == TC_DEMUX_SEQ_ADJUST2) { //new demux modes let transcode handle audio sync shift flag_avsync=0; flag_skip=0; } if(flag_avsync) { // get pts time stamp: ac_memcpy(buf, &buffer[20], 16); has_pts_dts=get_pts_dts(buf, &i_pts, &i_dts); if(has_pts_dts) { pts=(double)i_pts/90000.; } else { //fallback to scr time stamp: ac_memcpy(buf, &buffer[4], 6); pts = read_time_stamp(buf); } pts_diff = pts - resync_pts; //correction //FIXME pts_diff += av_fine_diff; if(pts_diff<0) { flag_skip=1; if(ipipe->verbose & TC_DEBUG) tc_log_msg(__FILE__, "(pid=%d) audio packet %06d for PU [%d] skipped (%.4f)", getpid(), j, ((k==0)? 0:k-1), pts-resync_pts); } else { //reset flag_skip=0; flag_avsync=0; if(ipipe->verbose) tc_log_msg(__FILE__, "(pid=%d) AV sync established for PU [%d] at PTS=%.4f (%.4f)", getpid(), k-1, pts, pts-resync_pts); } } //Post-processing: more audio packets? if(flag_append_audio) { //need to flush a few audio packets, if video ahead // get pts time stamp: ac_memcpy(buf, &buffer[20], 16); has_pts_dts=get_pts_dts(buf, &i_pts, &i_dts); if(has_pts_dts) { pts=(double)i_pts/90000.; } else { //fallback to scr time stamp: ac_memcpy(buf, &buffer[4], 6); pts = read_time_stamp(buf); } pts_diff = pts - resync_pts; if(pts_diff<0) { //append this packet flag_skip=0; if(ipipe->verbose & TC_DEBUG) tc_log_msg(__FILE__, "(pid=%d) audio packet %06d for PU [%d] appended (%.4f)", getpid(), j, ((k==0)? 0:k-1), pts-resync_pts); } else { //abort - all done flag_eos=1; if(ipipe->verbose) tc_log_msg(__FILE__, "(pid=%d) AV sync abandoned for PU [%d] at PTS=%.4f (%.4f)", getpid(), k-1, pts, pts-resync_pts); } } } //only go for audio in this phase if(flag_append_audio) goto flush_packet; /* ------------------------------------------------------------ * * (V) misc payload * * ------------------------------------------------------------*/ if(id == P_ID_PROG || id == P_ID_PADD) { payload_id=PACKAGE_NAV; // get pts time stamp: ac_memcpy(buf, &buffer[20], 16); has_pts_dts=get_pts_dts(buf, &i_pts, &i_dts); if(has_pts_dts) { pts=(double)i_pts/90000.; } else { //fallback to scr time stamp: ac_memcpy(buf, &buffer[4], 6); pts = read_time_stamp(buf); } //do not dump this packet flag_skip=1; } /* ------------------------------------------------------------ * * (VI) video payload * * ------------------------------------------------------------*/ if(id == P_ID_MPEG) { payload_id = PACKAGE_VIDEO; // get pts time stamp: ac_memcpy(buf, &buffer[4], 6); pts = read_time_stamp(buf); //read full packet header ac_memcpy(buf, &buffer[20], 16); has_pts_dts=get_pts_dts(buf, &i_pts, &i_dts); //need frame/field encoding information zz=scan_pack_ext(buffer); if(zz>0) flag_field_encoded=zz; //need precise number of pics in this sequence pack_picture_ctr = scan_pack_pics(buffer); seq_picture_ctr += pack_picture_ctr; frame_based_lpts = (seq_picture_ctr-1); //need this pack for subtitle PTS information if(flag_rewrite_scr && has_pts_dts) flag_force=1; // only process packets with pts/dts time stamp, since // they (all?) have a sequence start code if(has_pts_dts) { if (ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "(pid=%d) PTS-DTS detected in packet [%06d]", getpid(), j); // default first(=0) unit ? if(k==0) { --unit_seek; flag_sync_reset=1; if(ipipe->verbose & TC_DEBUG) tc_log_msg(__FILE__, "(pid=%d) MPEG sequence start code in packet %06d for PU [0]", getpid(), j); k++; } if(ptsverbose & TC_DEBUG) tc_log_msg(__FILE__, "(pid=%d) PTS reset (%.3f->%.3f) in packet %06d for PU [%d]", getpid(), ref_pts, pts, j, k); k++; } // only decrement sequence counter in right unit, i.e. // unit_seek=0; if(!unit_seek) --seq_seek; // flush all sequences until the end of the unit // or end of stream // or resync_seq2 is reached if(seq_seek==0) { //re read packet header ac_memcpy(buf, &buffer[20], 16); get_pts_dts(buf, &i_pts, &i_dts); resync_pts = (double) i_pts / 90000; if(!flag_flush) { // need to dump requested seq_dump sequences seq_seek=seq_dump; flag_flush = 1; flag_avsync = 1; // may be a useful info for the user if(ipipe->verbose) tc_log_msg(__FILE__, "(pid=%d) processing PU [%d], on at PTS=%.4f sec", getpid(), k-1, resync_pts); } else { // finished, all sequences flushed, switch // to audio packets post processing flag_append_audio = 1; flag_skip = 1; //flush mode on, but do not write this one // may be a useful info for the user if(ipipe->verbose) tc_log_msg(__FILE__, "(pid=%d) processing PU [%d], off at PTS=%.4f sec", getpid(), k-1, resync_pts); } } //--------------------------------------------------- //gather information on the sequences before flushing //--------------------------------------------------- if((demux_mode == TC_DEMUX_SEQ_FSYNC || demux_mode == TC_DEMUX_SEQ_FSYNC2) && flag_flush) { ptr = seq_register(sequence_ctr); zz=(flag_field_encoded==3)?(seq_picture_ctr-pack_picture_ctr): (seq_picture_ctr-pack_picture_ctr)/2; if(sequence_ctr) seq_update(ptr->prev, i_pts, zz, packet_ctr, flag_sync_active, hard_fps); //init sequence information structure for current sequence ptr->pts = i_pts; ptr->dts = i_dts; ptr->pics_first_packet = pack_picture_ctr; ptr->sync_reset = flag_sync_reset; //reset/update seq_picture_ctr = 0; packet_ctr = 0; ++sequence_ctr; //shift resync_pts, since sequence is dropped if(flag_sync_active==0) resync_pts=(double) i_pts / 90000; } //end TC_DEMUX_SEQ_FSYNC mode //--------------------------------------------------- //print out sequence information for frame navigation //--------------------------------------------------- if((demux_mode == TC_DEMUX_SEQ_LIST) && flag_flush) { ptr = seq_register(sequence_ctr); zz=(flag_field_encoded==3)?(seq_picture_ctr-pack_picture_ctr): (seq_picture_ctr-pack_picture_ctr)/2; if(sequence_ctr) seq_list(ptr->prev, i_pts, zz, packet_ctr, flag_sync_active); //init sequence information structure for current sequence ptr->pts = i_pts; ptr->dts = i_dts; ptr->pics_first_packet = pack_picture_ctr; ptr->sync_reset = flag_sync_reset; ptr->packet_ctr=j; //reset/update seq_picture_ctr = 0; packet_ctr = 0; ++sequence_ctr; //shift resync_pts, since sequence is dropped if(flag_sync_active==0) resync_pts=(double) i_pts / 90000; } //end TC_DEMUX_SEQ_LIST mode //reset sync pts, if no audio/substream has been found (0.6.0pre4) if(flag_sync_active==0 && demux_audio) { resync_pts=(double) i_pts / 90000; if(ipipe->verbose & TC_DEBUG) tc_log_msg(__FILE__, "new initial PTS=%f", resync_pts); } }// PTS-DTS flag yes ref_pts=pts; }// MPEG video packet /* ------------------------------------------------------------ * * (VII) evaluate scan results - flush packet * * ------------------------------------------------------------*/ flush_packet: if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "INFO: j=%05d, i=%05d, skip=%d, flush=%d, force=%d, pay=%3d, sid=0x%02x, eos=%d", j, i, flag_skip, flag_flush, flag_force, payload_id, id, flag_eos); //need to rewrite SCR pack header entry based on //frame_based_pts information for transcode: if(flag_rewrite_scr) scr_rewrite(&buffer[4], ((flag_field_encoded==3)?frame_based_lpts:frame_based_lpts/2)); //flush here: switch(demux_mode) { case TC_DEMUX_DEBUG: if((flag_flush && !flag_skip && (payload_id & select)) || flag_force) scan_pack_payload(buffer, packet_size, j, ipipe->verbose); break; case TC_DEMUX_DEBUG_ALL: scan_pack_payload(buffer, packet_size, j, ipipe->verbose); break; case TC_DEMUX_SEQ_FSYNC: case TC_DEMUX_SEQ_FSYNC2: if((flag_flush && !flag_skip && (payload_id & select)) || flag_force) { //count current sequence packets to be flushed ++packet_ctr; if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "flushing packet (%d/%d)", sequence_ctr, j); if(flush_buffer_write(ipipe->fd_out, buffer, packet_size) != packet_size) { tc_log_perror(__FILE__, "write program stream packet"); exit(1); } //reset flag_force=0; } break; case TC_DEMUX_SEQ_ADJUST: case TC_DEMUX_SEQ_ADJUST2: if((flag_flush && !flag_skip && (payload_id & select)) || flag_force) { if(tc_pwrite(ipipe->fd_out, buffer, packet_size) != packet_size) { tc_log_perror(__FILE__, "write program stream packet"); exit(1); } //reset flag_force=0; if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "writing packet %d", j); } else { ++i; if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "skipping packet %d", j); } break; case TC_DEMUX_SEQ_LIST: //count packs ++packet_ctr; // nothing to do break; case TC_DEMUX_OFF: if(tc_pwrite(ipipe->fd_out, buffer, packet_size) != packet_size) { tc_log_perror(__FILE__, "write program stream packet"); exit(1); } if(ipipe->verbose & TC_STATS) tc_log_msg(__FILE__, "writing packet %d", j); break; } //aborting? if(flag_eos) break; //total packs (2k each) counter ++j; } // process next packet/block if(ipipe->verbose & TC_SYNC) tc_log_msg(__FILE__, "EOS - flushing packet buffer"); //post processing if(demux_mode == TC_DEMUX_SEQ_FSYNC || demux_mode == TC_DEMUX_SEQ_FSYNC2) { seq_close(); flush_buffer_close(); } if(demux_mode == TC_DEMUX_SEQ_LIST) { ptr = seq_register(sequence_ctr); zz=(flag_field_encoded==3)?(seq_picture_ctr-pack_picture_ctr): (seq_picture_ctr-pack_picture_ctr)/2; if(ptr!=NULL && ptr->id) seq_list(ptr->prev, ref_pts, zz, packet_ctr, flag_sync_active); fflush(stdout); //summary seq_list_frames(); seq_close(); flush_buffer_close(); } //summary if(ipipe->verbose & TC_DEBUG) tc_log_msg(__FILE__, "(pid=%d) %d/%d packets discarded", getpid(), i, j); if(buffer!=NULL) free(buffer); return; }