diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/import/seqinfo.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/import/seqinfo.c | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/import/seqinfo.c b/debian/transcode/transcode-1.1.7/import/seqinfo.c new file mode 100644 index 00000000..d010b37f --- /dev/null +++ b/debian/transcode/transcode-1.1.7/import/seqinfo.c @@ -0,0 +1,674 @@ +/* + * seqinfo.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 "seqinfo.h" + +pthread_mutex_t seq_list_lock=PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t seq_ctr_lock=PTHREAD_MUTEX_INITIALIZER; + +seq_list_t *seq_list_head=NULL; +seq_list_t *seq_list_tail=NULL; + +static int _sfd=0; + +static double fps; +static int seq_ctr=0, drop_ctr=0; + +seq_list_t *seq_register(int id) +{ + + /* objectives: + =========== + + register new seq + + allocate space for new seq and establish backward reference + + + */ + + seq_list_t *ptr; + + pthread_mutex_lock(&seq_list_lock); + + // retrive a valid pointer from the pool + + if((ptr = tc_malloc(sizeof(seq_list_t))) == NULL) { + pthread_mutex_unlock(&seq_list_lock); + return(NULL); + } + + memset(ptr, 0, sizeof(seq_list_t)); + + ptr->status = BUFFER_EMPTY; + + ptr->next = NULL; + ptr->prev = NULL; + + ptr->id = id; + + if(seq_list_tail != NULL) + { + seq_list_tail->next = ptr; + ptr->prev = seq_list_tail; + } + + seq_list_tail = ptr; + + /* first seq registered must set seq_list_head */ + + if(seq_list_head == NULL) seq_list_head = ptr; + + pthread_mutex_unlock(&seq_list_lock); + + return(ptr); + +} + + +/* ------------------------------------------------------------------ */ + + +void seq_remove(seq_list_t *ptr) + +{ + + /* objectives: + =========== + + remove seq from chained list + + */ + + + if(ptr == NULL) return; // do nothing if null pointer + + pthread_mutex_lock(&seq_list_lock); + + if(ptr->prev != NULL) (ptr->prev)->next = ptr->next; + if(ptr->next != NULL) (ptr->next)->prev = ptr->prev; + + if(ptr == seq_list_tail) seq_list_tail = ptr->prev; + if(ptr == seq_list_head) seq_list_head = ptr->next; + + free(ptr); + ptr=NULL; + + pthread_mutex_unlock(&seq_list_lock); + +} + + +/* ------------------------------------------------------------------ */ + + +seq_list_t *seq_retrieve() + +{ + + /* objectives: + =========== + + get pointer to next full seq + + */ + + seq_list_t *ptr; + + pthread_mutex_lock(&seq_list_lock); + + ptr = seq_list_head; + + /* move along the chain and check for status */ + + while(ptr != NULL) + { + if(ptr->status == BUFFER_READY) + { + pthread_mutex_unlock(&seq_list_lock); + return(ptr); + } + ptr = ptr->next; + } + + pthread_mutex_unlock(&seq_list_lock); + + return(NULL); +} +/* ------------------------------------------------------------------ */ + + +static void seq_flush_thread(void) +{ + + seq_list_t *ptr, *tmp; + + ptr = seq_retrieve(); + + if(ptr!=NULL) { + + if(verbose & TC_SYNC) { + tc_log_msg(__FILE__, "syncinfo write (%d)", ptr->id); + } + + seq_write(ptr); + + // release valid pointer to pool + ptr->status = BUFFER_EMPTY; + + tmp=ptr->prev; + seq_remove(tmp); + + pthread_mutex_lock(&seq_ctr_lock); + --seq_ctr; + pthread_mutex_unlock(&seq_ctr_lock); + + } else + tc_log_error(__FILE__, "called but no work to do - this shouldn't happen"); + + return; +} + + +static long frame_ctr=0; +static long check_ctr=0; + + +/* ------------------------------------------------------------------ */ + +void seq_write(seq_list_t *ptr) +{ + + int i, k, clone[256]; + + sync_info_t sync_info; + + int tmp; + + int inc=0; + + double ftot_pts=0.0f; + + // ----------------- + // + // write to log file + // + // ----------------- + + // set clone flag for each frame: + // 0 = drop this frame + // 1 = unique frame + // N = use N copies of this frame + + + //default + for(i=0; i<ptr->enc_pics; ++i) clone[i]=1; + + if(ptr->adj_pics<0) { + + tmp = ptr->adj_pics; + inc = -ptr->enc_pics/ptr->adj_pics; + + while(-tmp>0) { + k=(-tmp*inc)%ptr->enc_pics; + clone[k]=0; + + ++tmp; + } + } + if(ptr->adj_pics>0) { + + tmp = ptr->adj_pics; + inc = (ptr->adj_pics<ptr->enc_pics) ? (int) ptr->enc_pics/ptr->adj_pics : 1; + + while(tmp>0) { + + k=(tmp*inc)%ptr->enc_pics; + ++clone[k]; + --tmp; + } + } + + //write out + + for(i=0; i<ptr->enc_pics; ++i) { + + //check for pulldown flag + sync_info.pulldown = ptr->pulldown; + + //master flag makes final decision + if(ptr->sync_active == 0) { + clone[i]=0; + sync_info.drop_seq=1; + sync_info.pulldown=0; + } else + sync_info.drop_seq=0; + + if(verbose & TC_PRIVATE) { + tc_log_msg(__FILE__, "[%ld] %d %d %d %ld", + frame_ctr, ptr->id, i, clone[i], check_ctr); + } + + drop_ctr += (int) (clone[i]-1); + + sync_info.sequence = ptr->id; + + sync_info.enc_frame = (long) frame_ctr++; + sync_info.adj_frame = (long) clone[i]; + + ftot_pts=(double) ptr->tot_pts/90000; + sync_info.dec_fps = (double) (ptr->tot_dec_pics)/ftot_pts; + sync_info.enc_fps = (ptr->ptime) ? (double) (ptr->enc_pics*90000)/ptr->ptime:0.0f; + + sync_info.pts = (double) ptr->tot_pts/90000; + + if((tmp=tc_pwrite(_sfd, (uint8_t *) &sync_info, sizeof(sync_info_t)))!= sizeof(sync_info_t)) { + tc_log_warn(__FILE__, "syncinfo write error (%d): %s", + tmp, strerror(errno)); + } + check_ctr += clone[i]; + + if(verbose & TC_SYNC && i==ptr->enc_pics-1) { + tc_log_msg(__FILE__, "sync data for sequence %d flushed [%ld]", + ptr->id, sync_info.enc_frame); + } + } + + if(verbose & TC_PRIVATE) { + tc_log_msg(__FILE__, "frames=%6ld seq=%4ld adj=%4d AV=%8.4f [fps] ratio= %.4f PTS= %.2f", + sync_info.enc_frame, sync_info.sequence, drop_ctr, + sync_info.dec_fps-fps, sync_info.enc_fps/fps, sync_info.pts); + } + + return; + +} + + +/* ------------------------------------------------------------------ */ + +void seq_update(seq_list_t *ptr, int end_pts, int pictures, int packets, int flag, int hard_fps) +{ + + int tmp; + + long int adj=0; + + long int request_pics=0, delay=0; + + double ftot_pts=0.0; + + //set basic parameter from inout variables + + ptr->seq_pics = pictures + ptr->pics_first_packet; + ptr->enc_pics = ptr->seq_pics; + ptr->packet_ctr = packets; + ptr->ptime = end_pts - ptr->pts; + ptr->sync_active = flag; //master flag + + if(ptr->ptime<=0 || ptr->id == 0) { + adj=0; + delay=0; + goto skip; + } + + if(ptr->id && ptr->sync_reset==0) { + + // (1) calculate total encoded frames: + ptr->tot_enc_pics = ptr->prev->tot_enc_pics + ptr->enc_pics; + + // (2) calculate total decoded frames: + ptr->tot_dec_pics = ptr->prev->tot_dec_pics + ptr->seq_pics; + + // (3) total number of packets: + ptr->tot_packet_ctr = ptr->prev->tot_packet_ctr + ptr->packet_ctr; + + // (4) total time since first sequence + ptr->tot_pts = ptr->prev->tot_pts + ptr->ptime; + + } else { + + // first sequence + ptr->tot_enc_pics = ptr->enc_pics; + ptr->tot_dec_pics = ptr->seq_pics; + ptr->tot_packet_ctr = ptr->packet_ctr; + ptr->tot_pts = ptr->ptime; + } + + // (5) total frames as requested by transcode + ftot_pts=(double) ptr->tot_pts/90000.; + request_pics = (long) (fps * ftot_pts); + + // (6) drop or clone frames of this sequence? + delay = request_pics - ptr->tot_dec_pics; + + adj=0; + + if(delay>0) { //frame cloning no limit yet + + if(delay<ptr->seq_pics) { + adj = delay; + } else { + adj = delay - (delay%ptr->seq_pics); + } + } + + if(delay<0) { //frame dropping, maximum seq_pics/2 + + tmp=-delay; + + if ( (-delay) >= (ptr->seq_pics/2)) { + adj = -(ptr->seq_pics/2); + } else { + adj = delay; + } + } + + //3:2 pulldown? + + // disable smooth dropping, pulldown, etc. This makes sense for variable + // framerates when the fps changes back and forth from 29.9 to 23.9 fps. The + // smooth dropping will work very badly then. + if (hard_fps == 0) { + + ptr->pulldown=0; + + if(adj == -3 && ptr->ptime == 45045 && ptr->seq_pics==15) ptr->pulldown = 1; + if(adj == -4 && ptr->ptime == 45045 && ptr->seq_pics==15) ptr->pulldown = 2; + if(adj == -2 && ptr->ptime == 6006 && ptr->seq_pics== 4) ptr->pulldown = 3; + if(adj == -1 && ptr->ptime == 39039 && ptr->seq_pics==11) ptr->pulldown = 4; + + //smooth drop/copy algorithm 2002-08-21 + if(ptr->pulldown==0) { + if(adj==-1 || adj==1 || adj==2) adj=0; + if(adj== 3) adj=1; + } + } + + skip: + + if(verbose & TC_PRIVATE) { + + tc_log_msg(__FILE__, "---------------------------------------------------------"); + tc_log_msg(__FILE__, "MPEG sequence: %d (reset=%d)", ptr->id, ptr->sync_reset); + tc_log_msg(__FILE__, "2k packets: %d (%d) | stream size %.2f MB", ptr->packet_ctr, ptr->tot_packet_ctr, (double) 2*ptr->tot_packet_ctr/(1<<10)); + tc_log_msg(__FILE__, "PTS: %f (abs) --> runtime=%f (sec)", (double) ptr->pts/90000, ftot_pts); + tc_log_msg(__FILE__, "sequence length: %f | ftime: %.4f (sec)", (double) ptr->ptime/90000, (double) ptr->ptime/90000/ptr->seq_pics); + tc_log_msg(__FILE__, "sequence frames: %2d (current=%.3f fps) %ld (average=%.3f fps)", ptr->seq_pics, (double) ptr->seq_pics*90000/ptr->ptime, ptr->ptime, (double) ptr->tot_dec_pics/ftot_pts); + tc_log_msg(__FILE__, "3:2 pulldown flag: %d (%f) | master_flag = %d", ptr->pulldown, fps * ftot_pts - ptr->tot_dec_pics, flag); + tc_log_msg(__FILE__, "total frames (encoded in sequence 0-%d): %d (requested=%ld) %ld --> adjust: %ld", ptr->id, ptr->tot_enc_pics, request_pics, delay, adj); + + } + + //save the adjustment: + ptr->tot_dec_pics +=adj; + ptr->seq_pics +=adj; + ptr->adj_pics =adj; + + // A-V shift at end of this sequence + ptr->av_sync = (ptr->tot_dec_pics - request_pics)/fps; + + + if(verbose & TC_PRIVATE) { + + tc_log_msg(__FILE__, "adjusted frames (decoded in sequence 0-%d): %d --> A-V: %.4f", ptr->id, ptr->tot_dec_pics, ptr->av_sync); + tc_log_msg(__FILE__, "---------------------------------------------------------"); + } + + + // ----------------- + // + // write to log file + // + // ----------------- + + ptr->status = BUFFER_READY; + + pthread_mutex_lock(&seq_ctr_lock); + ++seq_ctr; + pthread_mutex_unlock(&seq_ctr_lock); + + seq_flush_thread(); + + return; + +} + +/* ------------------------------------------------------------------ */ + +/******** + * FIXME: these two functions, and the printf()s below, are only used + * with the undocumented TC_DEMUX_SEQ_LIST (-M 5) mode. Is printf() + * appropriate, or for that matter is this even needed at all? --AC + ********/ + +static int seq_offset=0, unit_ctr=-1; + +void seq_list_frames() +{ + if(unit_ctr==-1) return; + tc_log_info(__FILE__, "%8ld video frame(s) in unit %d detected", + (long) frame_ctr, unit_ctr); +} + +/* ------------------------------------------------------------------ */ + +void seq_list(seq_list_t *ptr, int end_pts, int pictures, int packets, int flag) +{ + + int n, id; + + int tmp; + + long int adj=0; + + long int request_pics=0, delay=0; + + double ftot_pts=0.0; + + //set basic parameter from inout variables + + //------------------------------------------------------- + //for NTSC film + //we need to recalculate ptr->seq_pics + //------------------------------------------------------- + + id=ptr->id-seq_offset; + + ptr->seq_pics = pictures + ptr->pics_first_packet; + ptr->enc_pics = ptr->seq_pics; + + ptr->ptime = end_pts - ptr->pts; + ptr->sync_active = flag; //master flag + + //first sequence timing info may be wrong + if(ptr->ptime<=0 || id == 0 || ptr->sync_reset) { + adj=0; + delay=0; + goto skip; + } + + if(ptr->id && ptr->sync_reset==0) { + + // (1) calculate total encoded frames: + ptr->tot_enc_pics = ptr->prev->tot_enc_pics + ptr->enc_pics; + + // (2) calculate total decoded frames: + ptr->tot_dec_pics = ptr->prev->tot_dec_pics + ptr->seq_pics; + + // (3) total number of packets: + ptr->tot_packet_ctr = ptr->prev->tot_packet_ctr + ptr->packet_ctr; + + // (4) total time since first sequence + ptr->tot_pts = ptr->prev->tot_pts + ptr->ptime; + + } else { + + ptr->tot_enc_pics = ptr->enc_pics; + ptr->tot_dec_pics = ptr->seq_pics; + ptr->tot_packet_ctr = ptr->packet_ctr; + ptr->tot_pts = ptr->ptime; + } + + // (5) total frames as requested by transcode + ftot_pts=(double) ptr->tot_pts/90000; + request_pics = (long) (fps * ftot_pts); + + // (6) drop or clone frames of this sequence? + delay = request_pics - ptr->tot_dec_pics; + + adj=0; + + if(delay>0) { //frame cloning no limit yet + + if(delay<ptr->seq_pics) { + adj = delay; + } else { + adj = delay - (delay%ptr->seq_pics); + } + } + + if(delay<0) { //frame dropping, maximum seq_pics/2 + + tmp=-delay; + + if ( (-delay) >= (ptr->seq_pics/2)) { + adj = -(ptr->seq_pics/2); + } else { + adj = delay; + } + } + + ptr->pulldown=0; + + //smooth drop/copy algorithm 2002-06-04 + if((adj==1 || adj == -1 || adj==2 || adj== -2 || adj== -3 || adj== 3) + && ptr->pulldown==0) adj=0; + if(adj > 3 && ptr->pulldown==0) adj= 1; + if(adj < -3 && ptr->pulldown==0) adj=-1; + + //FIXME: drop all NTSC stuff, let transcode handle frame count + adj=0; + + skip: + + //save the adjustment: + ptr->tot_dec_pics +=adj; + ptr->seq_pics +=adj; + ptr->adj_pics =adj; + + // A-V shift at end of this sequence + ptr->av_sync = (ptr->tot_dec_pics - request_pics)/fps; + + + // ----------------- + // + // write to log file + // + // ----------------- + + ptr->status = BUFFER_READY; + + pthread_mutex_lock(&seq_ctr_lock); + ++seq_ctr; + pthread_mutex_unlock(&seq_ctr_lock); + + //print frame navigation information: + + if(ptr->sync_reset) { + + seq_list_frames(); + + frame_ctr=0; + seq_offset=ptr->id; + ++unit_ctr; + + id=0; + + } + + // tc_log_msg(__FILE__, "--- %d %d %d %d %d %d", delay, adj, ptr->seq_pics , ptr->enc_pics, ptr->pics_first_packet, pictures); + + // + // first sequence of stream or new unit + // + + if(id==0 || ptr->sync_reset) { + + for(n=0; n<ptr->enc_pics; ++n) + printf("%2d %6ld %5d %5d %6ld %3d\n", unit_ctr, (long) frame_ctr++, id, id, (long) ptr->packet_ctr, n); + + return; + } + + // + // regular sequence + // + + for(n=0; n<ptr->enc_pics; ++n) { + + if(n==0 || n==1) { + printf("%2d %6ld %5d %5d %6ld %3d\n", unit_ctr, (long) frame_ctr++, id, id-1, (long) ptr->prev->packet_ctr, ptr->prev->seq_pics+n); + } else { + printf("%2d %6ld %5d %5d %6ld %3d\n", unit_ctr, (long) frame_ctr++, id, id, (long) ptr->packet_ctr, n); + } + } + return; +} + +/* ------------------------------------------------------------------ */ + +int seq_init(const char *logfile, int _ext_sfd, double _fps, int _verbose) +{ + + //need to open the file + + if(logfile != NULL) { + if((_sfd = open(logfile, O_WRONLY|O_CREAT, 0666))<0) { + tc_log_error(__FILE__, "open logfile: %s", strerror(errno)); + return(-1); + } + } + + fps = _fps; + + //done + + if(_verbose & TC_DEBUG) + tc_log_msg(__FILE__, "open %s for frame sync information", logfile); + + return(0); +} + +/* ------------------------------------------------------------------ */ + +void seq_close() +{ + + if(_sfd != 0) close(_sfd); + _sfd=0; + + return; +} + |
