MythTV  0.26-pre
mpeg2fix.cpp
Go to the documentation of this file.
00001 //To Do
00002 //support missing audio frames
00003 //support analyze-only mode
00004 
00005 // C headers
00006 #include <cstdlib>
00007 #include <cstdio>
00008 
00009 // POSIC headers
00010 #include <fcntl.h>
00011 #include <unistd.h>
00012 #include <getopt.h>
00013 #include <stdint.h>
00014 #include <sys/stat.h>
00015 
00016 #include "config.h"
00017 #include "mpeg2fix.h"
00018 
00019 #include <QList>
00020 #include <QQueue>
00021 #include <QMap>
00022 #include <QFileInfo>
00023 
00024 #include "mythlogging.h"
00025 #include "mthread.h"
00026 
00027 #ifdef USING_MINGW
00028 #include <winsock2.h>
00029 #else
00030 #include <netinet/in.h>
00031 #endif
00032 
00033 #ifndef O_LARGEFILE
00034 #define O_LARGEFILE 0
00035 #endif
00036 
00037 #define ATTR_ALIGN(align) __attribute__ ((__aligned__ (align)))
00038 
00039 static void *my_malloc(unsigned size, mpeg2_alloc_t reason)
00040 {
00041     (void)reason;
00042     char * buf;
00043 
00044     if (size)
00045     {
00046         buf = (char *) malloc (size + 63 + sizeof (void **));
00047         if (buf)
00048         {
00049             char * align_buf;
00050             memset(buf, 0, size + 63 + sizeof (void **));
00051             align_buf = buf + 63 + sizeof (void **);
00052             align_buf -= (long)align_buf & 63;
00053             *(((void **)align_buf) - 1) = buf;
00054             return align_buf;
00055         }
00056     }
00057 
00058     return NULL;
00059 }
00060 
00061 static void my_av_print(void *ptr, int level, const char* fmt, va_list vl)
00062 {
00063     (void) ptr;
00064 
00065     static QString full_line("");
00066     char str[256];
00067 
00068     if (level > AV_LOG_INFO)
00069         return;
00070     vsprintf(str, fmt, vl);
00071 
00072     full_line += QString(str);
00073     if (full_line.endsWith("\n"))
00074     {
00075         full_line.truncate(full_line.length() - 1);
00076         LOG(VB_GENERAL, LOG_INFO, full_line);
00077         full_line = QString("");
00078     }
00079 }
00080 
00081 static QString PtsTime(int64_t pts)
00082 {
00083     bool is_neg = false;
00084     if (pts < 0)
00085     {
00086         pts = -pts;
00087         is_neg = true;
00088     }
00089     QString msg;
00090     return(msg.sprintf("%s%02d:%02d:%02d.%03d", (is_neg) ? "-" : "",
00091                 (unsigned int)(pts / 90000.) / 3600,
00092                 ((unsigned int)(pts / 90000.) % 3600) / 60,
00093                 ((unsigned int)(pts / 90000.) % 3600) % 60,
00094                 (((unsigned int)(pts / 90.) % 3600000) % 60000) % 1000));
00095 }
00096 
00097 PTSOffsetQueue::PTSOffsetQueue(int vidid, QList<int> keys, int64_t initPTS)
00098 {
00099     QList<int>::iterator it;
00100     poq_idx_t idx;
00101     vid_id = vidid;
00102     keyList = keys;
00103     keyList.append(vid_id);
00104 
00105     idx.newPTS = initPTS;
00106     idx.pos_pts = 0;
00107     idx.framenum = 0;
00108     idx.type = 0;
00109 
00110     for (it = keyList.begin(); it != keyList.end(); ++it)
00111         offset[*it].push_back(idx);
00112 }
00113 
00114 int64_t PTSOffsetQueue::Get(int idx, AVPacket *pkt)
00115 {
00116     QList<poq_idx_t>::iterator it;
00117     int64_t value = offset[idx].first().newPTS;
00118     bool done = false;
00119 
00120     if (!pkt)
00121         return value;
00122 
00123     //Be aware: the key for offset can be either a file position OR a PTS
00124     //The type is defined by type (0==PTS, 1==Pos)
00125     while (offset[idx].count() > 1 && !done)
00126     {
00127         it = ++offset[idx].begin();
00128         if ((((*it).type == 0) && (pkt->pts >= (*it).pos_pts) /* PTS type */) ||
00129             (((*it).type == 1) /* Pos type */ &&
00130              ((pkt->pos >= (*it).pos_pts) || (pkt->duration > (*it).framenum))))
00131         {
00132             offset[idx].pop_front();
00133             value = offset[idx].first().newPTS;
00134         }
00135         else
00136             done = true;
00137     }
00138     return value;
00139 }
00140 
00141 void PTSOffsetQueue::SetNextPTS(int64_t newPTS, int64_t atPTS)
00142 {
00143     QList<int>::iterator it;
00144     poq_idx_t idx;
00145 
00146     idx.newPTS = newPTS;
00147     idx.pos_pts = atPTS;
00148     idx.type = 0;
00149     idx.framenum = 0;
00150 
00151     for (it = keyList.begin(); it != keyList.end(); ++it)
00152         offset[*it].push_back(idx);
00153 }
00154 
00155 void PTSOffsetQueue::SetNextPos(int64_t newPTS, AVPacket &pkt)
00156 {
00157     QList<int>::iterator it;
00158     int64_t delta = MPEG2fixup::diff2x33(newPTS, offset[vid_id].last().newPTS);
00159     poq_idx_t idx;
00160 
00161     idx.pos_pts = pkt.pos;
00162     idx.framenum = pkt.duration;
00163     idx.type = 1;
00164 
00165     LOG(VB_FRAME, LOG_INFO, QString("Offset %1 -> %2 (%3) at %4")
00166             .arg(PtsTime(offset[vid_id].last().newPTS))
00167             .arg(PtsTime(newPTS)).arg(PtsTime(delta)).arg(pkt.pos));
00168     for (it = keyList.begin(); it != keyList.end(); ++it)
00169     {
00170         idx.newPTS = newPTS;
00171         offset[*it].push_back(idx);
00172         idx.newPTS = delta;
00173         orig[*it].push_back(idx);
00174     }
00175 }
00176 
00177 int64_t PTSOffsetQueue::UpdateOrigPTS(int idx, int64_t &origPTS, AVPacket &pkt)
00178 {
00179     int64_t delta = 0;
00180     QList<poq_idx_t> *dltaList = &orig[idx];
00181     while (dltaList->count() && 
00182            (pkt.pos     >= dltaList->first().pos_pts ||
00183             pkt.duration > dltaList->first().framenum))
00184     {
00185         if (dltaList->first().newPTS >= 0)
00186             ptsinc((uint64_t *)&origPTS, 300 * dltaList->first().newPTS);
00187         else
00188             ptsdec((uint64_t *)&origPTS, -300 * dltaList->first().newPTS);
00189         delta += dltaList->first().newPTS;
00190         dltaList->pop_front();
00191         LOG(VB_PROCESS, LOG_INFO,
00192             QString("Moving PTS offset of stream %1 by %2")
00193                 .arg(idx).arg(PtsTime(delta)));
00194     }
00195     return (delta);
00196 }
00197 
00198 MPEG2fixup::MPEG2fixup(const QString &inf, const QString &outf,
00199                        frm_dir_map_t *deleteMap,
00200                        const char *fmt, int norp, int fixPTS, int maxf,
00201                        bool showprog, int otype, void (*update_func)(float),
00202                        int (*check_func)())
00203 {
00204     displayFrame = 0;
00205 
00206     infile = inf;
00207     rx.outfile = outf;
00208     rx.done = 0;
00209     format = fmt;
00210     no_repeat = norp;
00211     fix_PTS = fixPTS;
00212     maxframes = maxf;
00213     rx.otype = otype;
00214 
00215     real_file_end = file_end = false;
00216 
00217     use_secondary = false;
00218     framenum = 0;
00219     discard = 0;
00220     if (deleteMap && deleteMap->count())
00221     {
00222         delMap = *deleteMap;
00223         if (delMap.contains(0))
00224         {
00225             discard = 1;
00226             delMap.remove(0);
00227         }
00228         if (delMap.begin().value() == MARK_CUT_END)
00229             discard = 1;
00230         use_secondary = true;
00231     }
00232 
00233     ext_count = 0;
00234     vid_id = -1;
00235     mpeg2_malloc_hooks(my_malloc, NULL);
00236     header_decoder = mpeg2_init();
00237     img_decoder = mpeg2_init();
00238 
00239     av_register_all();
00240     av_log_set_callback(my_av_print);
00241 
00242     pthread_mutex_init(&rx.mutex, NULL);
00243     pthread_cond_init(&rx.cond, NULL);
00244 
00245     //await multiplexer initialization (prevent a deadlock race)
00246     pthread_mutex_lock(&rx.mutex);
00247     pthread_create(&thread, NULL, ReplexStart, this);
00248     pthread_cond_wait(&rx.cond, &rx.mutex);
00249     pthread_mutex_unlock(&rx.mutex);
00250 
00251     //initialize progress stats
00252     showprogress = showprog;
00253     update_status = update_func;
00254     check_abort = check_func;
00255     if (showprogress || update_status)
00256     {
00257         if (update_status)
00258         {
00259             status_update_time = 20;
00260             update_status(0);
00261         }
00262         else
00263             status_update_time = 5;
00264         statustime = QDateTime::currentDateTime();
00265         statustime = statustime.addSecs(status_update_time);
00266 
00267         const QFileInfo finfo(inf);
00268         filesize = finfo.size();
00269     }
00270 }
00271 
00272 MPEG2fixup::~MPEG2fixup()
00273 {
00274     mpeg2_close(header_decoder);
00275     mpeg2_close(img_decoder);
00276 
00277     if (inputFC)
00278         avformat_close_input(&inputFC);
00279 
00280     MPEG2frame *tmpFrame;
00281 
00282     while (vFrame.count())
00283     {
00284         tmpFrame = vFrame.takeFirst();
00285         delete tmpFrame;
00286     }
00287 
00288     while (vSecondary.count())
00289     {
00290         tmpFrame = vSecondary.takeFirst();
00291         delete tmpFrame;
00292     }
00293 
00294     for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
00295     {
00296         FrameList *af = (*it);
00297         while (af->count())
00298         {
00299             tmpFrame = af->takeFirst();
00300             delete tmpFrame;
00301         }
00302         delete af;
00303     }
00304 
00305     while (framePool.count())
00306         delete framePool.dequeue();
00307 }
00308 
00309 //#define MPEG2trans_DEBUG
00310 #define MATCH_HEADER(ptr) (((ptr)[0] == 0x00) && ((ptr)[1] == 0x00) && ((ptr)[2] == 0x01))
00311 
00312 static void SETBITS(unsigned char *ptr, long value, int num)
00313 {
00314     static int sb_pos;
00315     static unsigned char *sb_ptr = 0;
00316     uint32_t sb_long, mask;
00317     int offset, offset_r, offset_b;
00318 
00319     if (ptr != 0)
00320     {
00321         sb_ptr = ptr;
00322         sb_pos = 0;
00323     }
00324 
00325     offset = sb_pos >> 3;
00326     offset_r = sb_pos & 0x07;
00327     offset_b = 32 - offset_r;
00328     mask = ~(((1 << num) - 1) << (offset_b - num));
00329     sb_long = ntohl(*((uint32_t *) (sb_ptr + offset)));
00330     value = value << (offset_b - num);
00331     sb_long = (sb_long & mask) + value;
00332     *((uint32_t *)(sb_ptr + offset)) = htonl(sb_long);
00333 }
00334 
00335 void MPEG2fixup::dec2x33(int64_t *pts1, int64_t pts2)
00336 {
00337     *pts1 = udiff2x33(*pts1, pts2);
00338 }
00339 
00340 void MPEG2fixup::inc2x33(int64_t *pts1, int64_t pts2)
00341 {
00342     *pts1 = (*pts1 + pts2) % MAX_PTS;
00343 }
00344 
00345 int64_t MPEG2fixup::udiff2x33(int64_t pts1, int64_t pts2)
00346 {
00347     int64_t diff;
00348 
00349     diff = pts1 - pts2;
00350 
00351     if (diff < 0){
00352         diff = MAX_PTS + diff;
00353     }
00354     return (diff % MAX_PTS);
00355 }
00356 
00357 int64_t MPEG2fixup::diff2x33(int64_t pts1, int64_t pts2)
00358 {
00359     switch (cmp2x33(pts1, pts2))
00360     {
00361         case 0:
00362             return 0;
00363             break;
00364 
00365         case 1:
00366         case -2:
00367             return (pts1 - pts2);
00368             break;
00369 
00370         case 2:
00371             return (pts1 + MAX_PTS - pts2);
00372             break;
00373 
00374         case -1:
00375             return (pts1 - (pts2 + MAX_PTS));
00376             break;
00377     }
00378 
00379     return 0;
00380 }
00381 
00382 int64_t MPEG2fixup::add2x33(int64_t pts1, int64_t pts2)
00383 {
00384     int64_t tmp = pts1 + pts2;
00385     if (tmp >= 0)
00386         return (pts1 + pts2) % MAX_PTS;
00387     return (tmp + MAX_PTS);
00388 }
00389 
00390 int MPEG2fixup::cmp2x33(int64_t pts1, int64_t pts2)
00391 {
00392     int ret;
00393 
00394     if (pts1 > pts2)
00395     {
00396         if ((uint64_t)(pts1 - pts2) > MAX_PTS/2)
00397             ret = -1;
00398         else 
00399             ret = 1;
00400     }
00401     else if (pts1 == pts2)
00402         ret = 0; 
00403     else
00404     {
00405         if ((uint64_t)(pts2 - pts1) > MAX_PTS/2)
00406             ret = 2;
00407         else  
00408             ret = -2;
00409     }
00410     return ret;
00411 }
00412 
00413 int MPEG2fixup::FindMPEG2Header(uint8_t *buf, int size, uint8_t code)
00414 {
00415     int i;
00416 
00417     for (i = 0; i < size; i++)
00418     {
00419         if (MATCH_HEADER(buf + i) && buf[i + 3] == code)
00420             return i;
00421     }
00422 
00423     return 0;
00424 }
00425 
00426 //fill_buffers will signal the main thread to start decoding again as soon
00427 //as it runs out of buffers.  It will then wait for the buffer to completely
00428 //fill before returning.  In this way, the 2 threads are never running
00429 // concurrently
00430 static int fill_buffers(void *r, int finish)
00431 {
00432     MPEG2replex *rx = (MPEG2replex *)r;
00433 
00434     if (finish)
00435         return 0;
00436 
00437     return (rx->WaitBuffers());
00438 }
00439 
00440 MPEG2replex::MPEG2replex() :
00441     done(0),      otype(0),
00442     ext_count(0), mplex(0)
00443 {
00444     memset(&vrbuf, 0, sizeof(vrbuf));
00445     memset(extrbuf, 0, sizeof(extrbuf));
00446     memset(&index_vrbuf, 0, sizeof(index_vrbuf));
00447     memset(index_extrbuf, 0, sizeof(index_extrbuf));
00448     memset(exttype, 0, sizeof(exttype));
00449     memset(exttypcnt, 0, sizeof(exttypcnt));
00450     memset(extframe, 0, sizeof(extframe));
00451     memset(&seq_head, 0, sizeof(seq_head)); 
00452 }
00453 
00454 MPEG2replex::~MPEG2replex()
00455 {
00456     if (vrbuf.size)
00457         ring_destroy(&vrbuf);
00458     if (index_vrbuf.size)
00459         ring_destroy(&index_vrbuf);
00460     
00461     for (int i = 0; i < ext_count; i++)
00462     {
00463         if (extrbuf[i].size)
00464             ring_destroy(&extrbuf[i]);
00465         if (index_extrbuf[i].size)
00466             ring_destroy(&index_extrbuf[i]);
00467     }
00468 }
00469 
00470 int MPEG2replex::WaitBuffers()
00471 {
00472     pthread_mutex_lock( &mutex );
00473     while (1)
00474     {
00475         int i, ok = 1;
00476 
00477         if (ring_avail(&index_vrbuf) < sizeof(index_unit))
00478             ok = 0;
00479 
00480         for (i = 0; i < ext_count; i++)
00481             if (ring_avail(&index_extrbuf[i]) < sizeof(index_unit))
00482                 ok = 0;
00483 
00484         if (ok || done)
00485             break;
00486 
00487         pthread_cond_signal(&cond);
00488         pthread_cond_wait(&cond, &mutex);
00489     }
00490     pthread_mutex_unlock(&mutex);
00491 
00492     if (done)
00493     {
00494         finish_mpg(mplex);
00495         pthread_exit(NULL);
00496     }
00497 
00498     return 0;
00499 }
00500 
00501 void *MPEG2fixup::ReplexStart(void *data)
00502 {
00503     MThread::ThreadSetup("MPEG2Replex");
00504     MPEG2fixup *m2f = (MPEG2fixup *) data;
00505     m2f->rx.Start();
00506     MThread::ThreadCleanup();
00507     return NULL;
00508 }
00509 
00510 void MPEG2replex::Start()
00511 {
00512     int start = 1;
00513     multiplex_t mx;
00514 
00515     //array defines number of allowed audio streams
00516     // note that although only 1 stream is currently supported, multiplex.c
00517     // expects the size to by N_AUDIO
00518     int ext_ok[N_AUDIO];
00519     int video_ok = 0;
00520 
00521     //seq_head should be set only for the 1st sequence header.  If a new
00522     // seq header comes which is different, we are screwed.
00523 
00524 
00525     int video_delay = 0, audio_delay = 0;
00526     int fd_out;
00527 
00528     memset(&mx, 0, sizeof(mx));
00529     memset(ext_ok, 0, sizeof(ext_ok));
00530 
00531     mx.priv = (void *)this;
00532 
00533     fd_out = open(outfile.toLocal8Bit().constData(),
00534                   O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
00535 
00536     //await buffer fill
00537     pthread_mutex_lock(&mutex);
00538     pthread_cond_signal(&cond);
00539     pthread_cond_wait(&cond, &mutex);
00540     pthread_mutex_unlock(&mutex);
00541 
00542     mplex = &mx;
00543 
00544     init_multiplex(&mx, &seq_head, extframe, exttype, exttypcnt,
00545                    video_delay, audio_delay, fd_out, fill_buffers,
00546                    &vrbuf, &index_vrbuf, extrbuf, index_extrbuf, otype);
00547     setup_multiplex(&mx);
00548 
00549     while (1)
00550     {
00551         check_times( &mx, &video_ok, ext_ok, &start);
00552         write_out_packs( &mx, video_ok, ext_ok);
00553     }
00554 }
00555 
00556 #define INDEX_BUF (sizeof(index_unit) * 200)
00557 void MPEG2fixup::InitReplex()
00558 {
00559     // index_vrbuf contains index_units which describe a video frame
00560     //   it also contains the start pos of the next frame
00561     // index_arbuf only uses, pts, framesize, length, start, (active, err)
00562 
00563     //this should support > 100 frames
00564     uint32_t memsize = vFrame.first()->mpeg2_seq.width *
00565                        vFrame.first()->mpeg2_seq.height * 10;
00566     ring_init(&rx.vrbuf, memsize);
00567     ring_init(&rx.index_vrbuf, INDEX_BUF);
00568 
00569     memset(rx.exttype, 0, sizeof(rx.exttype));
00570     memset(rx.exttypcnt, 0, sizeof(rx.exttypcnt));
00571     int mp2_count = 0, ac3_count = 0;
00572     for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
00573     {
00574         int i = aud_map[it.key()];
00575         AVDictionaryEntry *metatag =
00576             av_dict_get(inputFC->streams[it.key()]->metadata,
00577                         "language", NULL, 0);
00578         char *lang = metatag ? metatag->value : (char *)"";
00579         ring_init(&rx.extrbuf[i], memsize / 5);
00580         ring_init(&rx.index_extrbuf[i], INDEX_BUF);
00581         rx.extframe[i].set = 1;
00582         rx.extframe[i].bit_rate = getCodecContext(it.key())->bit_rate;
00583         rx.extframe[i].framesize = (*it)->first()->pkt.size;
00584         strncpy(rx.extframe[i].language, lang, 4);
00585         switch(GetStreamType(it.key()))
00586         {
00587             case CODEC_ID_MP2:
00588             case CODEC_ID_MP3:
00589                 rx.exttype[i] = 2;
00590                 rx.exttypcnt[i] = mp2_count++;
00591                 break;
00592             case CODEC_ID_AC3:
00593                 rx.exttype[i] = 1;
00594                 rx.exttypcnt[i] = ac3_count++;
00595                 break;
00596         }
00597     }
00598 
00599     //bit_rate/400
00600     rx.seq_head.bit_rate = vFrame.first()->mpeg2_seq.byte_rate / 50;
00601     rx.seq_head.frame_rate = (vFrame.first()->mpeg2_seq.frame_period +
00602                          26999999ULL) / vFrame.first()->mpeg2_seq.frame_period;
00603 
00604     rx.ext_count = ext_count;
00605 }
00606 
00607 void MPEG2fixup::FrameInfo(MPEG2frame *f)
00608 {
00609     QString msg = QString("Id:%1 %2 V:%3").arg(f->pkt.stream_index)
00610                     .arg(PtsTime(f->pkt.pts))
00611                     .arg(ring_free(&rx.index_vrbuf) / sizeof(index_unit));
00612 
00613     if (ext_count)
00614     {
00615         msg += " EXT:";
00616         for (int i = 0; i < ext_count; i++)
00617             msg += QString(" %2")
00618                    .arg(ring_free(&rx.index_extrbuf[i]) / sizeof(index_unit));
00619     }
00620     LOG(VB_RPLXQUEUE, LOG_INFO, msg);
00621 }
00622 
00623 int MPEG2fixup::AddFrame(MPEG2frame *f)
00624 {
00625     index_unit iu;
00626     ringbuffer *rb = 0, *rbi = 0;
00627     int id = f->pkt.stream_index;
00628 
00629     memset(&iu, 0, sizeof(index_unit));
00630     iu.frame_start = 1;
00631 
00632     if (id == vid_id)
00633     {
00634         rb = &rx.vrbuf;
00635         rbi = &rx.index_vrbuf;
00636         iu.frame = GetFrameTypeN(f);
00637         iu.seq_header = f->isSequence;
00638         iu.gop = f->isGop;
00639 
00640         iu.gop_off = f->gopPos - f->pkt.data;
00641         iu.frame_off = f->framePos - f->pkt.data;
00642         iu.dts = f->pkt.dts * 300;
00643     }
00644     else if (GetStreamType(id) == CODEC_ID_MP2 ||
00645              GetStreamType(id) == CODEC_ID_MP3 ||
00646              GetStreamType(id) == CODEC_ID_AC3)
00647     {
00648         rb = &rx.extrbuf[aud_map[id]];
00649         rbi = &rx.index_extrbuf[aud_map[id]];
00650         iu.framesize = f->pkt.size;
00651     }
00652 
00653     if (!rb || !rbi)
00654     {
00655         LOG(VB_GENERAL, LOG_ERR, "Ringbuffer pointers empty. No stream found");
00656         return 1;
00657     }
00658 
00659     iu.active = 1;
00660     iu.length = f->pkt.size;
00661     iu.pts = f->pkt.pts * 300;
00662     pthread_mutex_lock( &rx.mutex );
00663 
00664     FrameInfo(f);
00665     while (ring_free(rb) < (unsigned int)f->pkt.size ||
00666             ring_free(rbi) < sizeof(index_unit))
00667     {
00668         int i, ok = 1;
00669 
00670         if (rbi != &rx.index_vrbuf &&
00671                 ring_avail(&rx.index_vrbuf) < sizeof(index_unit))
00672             ok = 0;
00673 
00674         for (i = 0; i < ext_count; i++)
00675             if (rbi != &rx.index_extrbuf[i] &&
00676                     ring_avail(&rx.index_extrbuf[i]) < sizeof(index_unit))
00677                 ok = 0;
00678 
00679         if (!ok && ring_free(rb) < (unsigned int)f->pkt.size &&
00680                     ring_free(rbi) >= sizeof(index_unit))
00681         {
00682             // increase memory to avoid deadlock
00683             unsigned int inc_size = 10 * (unsigned int)f->pkt.size;
00684             LOG(VB_GENERAL, LOG_NOTICE,
00685                 QString("Increasing ringbuffer size by %1 to avoid deadlock")
00686                     .arg(inc_size));
00687 
00688             if (!ring_reinit(rb, rb->size + inc_size))
00689                 ok = 1;
00690         }
00691         if (!ok)
00692         {
00693             pthread_mutex_unlock( &rx.mutex );
00694             //deadlock
00695             LOG(VB_GENERAL, LOG_ERR,
00696                 "Deadlock detected.  One buffer is full when "
00697                 "the other is empty!  Aborting");
00698             return 1;
00699         }
00700 
00701         pthread_cond_signal(&rx.cond);
00702         pthread_cond_wait(&rx.cond, &rx.mutex);
00703 
00704         FrameInfo(f);
00705     }
00706 
00707     if (ring_write(rb, f->pkt.data, f->pkt.size)<0){
00708         pthread_mutex_unlock( &rx.mutex );
00709         LOG(VB_GENERAL, LOG_ERR,
00710             QString("Ring buffer overflow %1").arg(rb->size));
00711         return 1;
00712     }
00713 
00714     if (ring_write(rbi, (uint8_t *)&iu, sizeof(index_unit))<0){
00715         pthread_mutex_unlock( &rx.mutex );
00716         LOG(VB_GENERAL, LOG_ERR,
00717             QString("Ring buffer overflow %1").arg(rbi->size));
00718         return 1;
00719     }
00720     pthread_mutex_unlock(&rx.mutex);
00721     last_written_pos = f->pkt.pos;
00722     return 0;
00723 }
00724 
00725 bool MPEG2fixup::InitAV(QString inputfile, const char *type, int64_t offset)
00726 {
00727     int ret;
00728     QByteArray ifarray = inputfile.toLocal8Bit();
00729     const char *ifname = ifarray.constData();
00730 
00731     AVInputFormat *fmt = NULL;
00732 
00733     if (type)
00734         fmt = av_find_input_format(type);
00735 
00736     // Open recording
00737     LOG(VB_GENERAL, LOG_INFO, QString("Opening %1").arg(inputfile));
00738 
00739     inputFC = NULL;
00740 
00741     ret = avformat_open_input(&inputFC, ifname, fmt, NULL);
00742     if (ret)
00743     {
00744         LOG(VB_GENERAL, LOG_ERR,
00745             QString("Couldn't open input file, error #%1").arg(ret));
00746         return false;
00747     }
00748 
00749     mkvfile = !strcmp(inputFC->iformat->name, "mkv") ? 1 : 0;
00750 
00751     if (offset)
00752         av_seek_frame(inputFC, vid_id, offset, AVSEEK_FLAG_BYTE);
00753 
00754     // Getting stream information
00755     ret = avformat_find_stream_info(inputFC, NULL);
00756     if (ret < 0)
00757     {
00758         LOG(VB_GENERAL, LOG_ERR,
00759             QString("Couldn't get stream info, error #%1").arg(ret));
00760         avformat_close_input(&inputFC);
00761         inputFC = NULL;
00762         return false;
00763     }
00764 
00765     // Dump stream information
00766     if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_INFO))
00767         av_dump_format(inputFC, 0, ifname, 0);
00768 
00769     for (unsigned int i = 0; i < inputFC->nb_streams; i++)
00770     {
00771         switch (inputFC->streams[i]->codec->codec_type)
00772         {
00773             case AVMEDIA_TYPE_VIDEO:
00774                 if (vid_id == -1)
00775                     vid_id = i;
00776                 break;
00777 
00778             case AVMEDIA_TYPE_AUDIO:
00779                 if (inputFC->streams[i]->codec->channels == 0)
00780                 {
00781                     LOG(VB_GENERAL, LOG_ERR,
00782                         QString("Skipping invalid audio stream: %1").arg(i));
00783                     break;
00784                 }
00785                 if (inputFC->streams[i]->codec->codec_id == CODEC_ID_AC3 ||
00786                     inputFC->streams[i]->codec->codec_id == CODEC_ID_MP3 ||
00787                     inputFC->streams[i]->codec->codec_id == CODEC_ID_MP2)
00788                 {
00789                     aud_map[i] = ext_count++;
00790                     aFrame[i] = new FrameList();
00791                 }
00792                 else
00793                     LOG(VB_GENERAL, LOG_ERR,
00794                         QString("Skipping unsupported audio stream: %1")
00795                             .arg(inputFC->streams[i]->codec->codec_id));
00796                 break;
00797             default:
00798                 LOG(VB_GENERAL, LOG_ERR,
00799                     QString("Skipping unsupported codec %1 on stream %2")
00800                         .arg(inputFC->streams[i]->codec->codec_type).arg(i));
00801                 break;
00802         }
00803     }
00804 
00805     return true;
00806 }
00807 
00808 void MPEG2fixup::SetFrameNum(uint8_t *ptr, int num)
00809 {
00810     SETBITS(ptr + 4, num, 10);
00811 }
00812 
00813 void MPEG2fixup::AddSequence(MPEG2frame *frame1, MPEG2frame *frame2)
00814 {
00815     if (frame1->isSequence || !frame2->isSequence)
00816         return;
00817 
00818     int head_size = (frame2->framePos - frame2->pkt.data);
00819 
00820     frame1->ensure_size(frame1->pkt.size + head_size);
00821     memmove(frame1->pkt.data + head_size, frame1->pkt.data, frame1->pkt.size);
00822     memcpy(frame1->pkt.data, frame2->pkt.data, head_size);
00823     frame1->pkt.size += head_size;
00824     ProcessVideo(frame1, header_decoder);
00825 #if 0
00826     if (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY))
00827     {
00828         static int count = 0;
00829         QString filename = QString("hdr%1.yuv").arg(count++);
00830         WriteFrame(filename, &frame1->pkt);
00831     }
00832 #endif
00833 }
00834 
00835 int MPEG2fixup::ProcessVideo(MPEG2frame *vf, mpeg2dec_t *dec)
00836 {
00837     int state = -1;
00838     int last_pos = 0;
00839     mpeg2_info_t *info;
00840 
00841     if (dec == header_decoder)
00842     {
00843         mpeg2_reset(dec, 0);
00844         vf->isSequence = 0;
00845         vf->isGop = 0;
00846     }
00847 
00848     info = (mpeg2_info_t *)mpeg2_info(dec);
00849 
00850     mpeg2_buffer(dec, vf->pkt.data, vf->pkt.data + vf->pkt.size);
00851 
00852     while (state != STATE_PICTURE)
00853     {
00854         state = mpeg2_parse(dec);
00855 
00856         if (dec == header_decoder)
00857         {
00858             switch (state)
00859             {
00860 
00861                 case STATE_SEQUENCE:
00862                 case STATE_SEQUENCE_MODIFIED:
00863                 case STATE_SEQUENCE_REPEATED:
00864                     memcpy(&vf->mpeg2_seq, info->sequence,
00865                            sizeof(mpeg2_sequence_t));
00866                     vf->isSequence = 1;
00867                     break;
00868 
00869                 case STATE_GOP:
00870                     memcpy(&vf->mpeg2_gop, info->gop, sizeof(mpeg2_gop_t));
00871                     vf->isGop = 1;
00872                     vf->gopPos = vf->pkt.data + last_pos;
00873                     //pd->adjustFrameCount=0;
00874                     break;
00875 
00876                 case STATE_PICTURE:
00877                     memcpy(&vf->mpeg2_pic, info->current_picture,
00878                            sizeof(mpeg2_picture_t));
00879                     vf->framePos = vf->pkt.data + last_pos;
00880                     break;
00881 
00882                 case STATE_BUFFER:
00883                     LOG(VB_GENERAL, LOG_WARNING,
00884                         "Warning: partial frame found!");
00885                     return 1;
00886             }
00887         }
00888         else if (state == STATE_BUFFER)
00889         {
00890             WriteData("abort.dat", vf->pkt.data, vf->pkt.size);
00891             LOG(VB_GENERAL, LOG_ERR,
00892                 QString("Failed to decode frame.  Position was: %1")
00893                     .arg(last_pos));
00894             return -1;
00895         } 
00896         last_pos = (vf->pkt.size - mpeg2_getpos(dec)) - 4;
00897     }
00898 
00899     if (dec != header_decoder)
00900     {
00901         while (state != STATE_BUFFER)
00902             state = mpeg2_parse(dec);
00903         if (info->display_picture)
00904         {
00905             // This is a hack to force libmpeg2 to finish writing out the slice
00906             // without it, the final row doesn't get put into the disp_pic
00907             // (for B-frames only).
00908             // 0xb2 is 'user data' and is actually illegal between pic
00909             // headers, but it is just discarded by libmpeg2
00910             uint8_t tmp[8] = {0x00, 0x00, 0x01, 0xb2, 0xff, 0xff, 0xff, 0xff};
00911             mpeg2_buffer(dec, tmp, tmp + 8);
00912             mpeg2_parse(dec);
00913         }   
00914     }
00915 
00916     if (VERBOSE_LEVEL_CHECK(VB_DECODE, LOG_INFO))
00917     {
00918         QString msg = QString("");
00919 #if 0
00920         msg += QString("unused:%1 ") .arg(vf->pkt.size - mpeg2_getpos(dec));
00921 #endif
00922 
00923         if (vf->isSequence)
00924             msg += QString("%1x%2 P:%3 ").arg(info->sequence->width)
00925                 .arg(info->sequence->height).arg(info->sequence->frame_period);
00926 
00927         if (info->gop)
00928         {
00929             QString gop;
00930             gop.sprintf("%02d:%02d:%02d:%03d ",
00931                         info->gop->hours, info->gop->minutes,
00932                         info->gop->seconds, info->gop->pictures);
00933             msg += gop;
00934         }
00935         if (info->current_picture) {
00936             int ct = info->current_picture->flags & PIC_MASK_CODING_TYPE;
00937             char coding_type = (ct == PIC_FLAG_CODING_TYPE_I) ? 'I' :
00938                                 ((ct == PIC_FLAG_CODING_TYPE_P) ? 'P' :
00939                                  ((ct == PIC_FLAG_CODING_TYPE_B) ? 'B' :
00940                                   ((ct == PIC_FLAG_CODING_TYPE_D) ?'D' : 'X')));
00941             char top_bottom = (info->current_picture->flags & 
00942                                PIC_FLAG_TOP_FIELD_FIRST) ? 'T' : 'B';
00943             char progressive = (info->current_picture->flags &
00944                                 PIC_FLAG_PROGRESSIVE_FRAME) ? 'P' : '_';
00945             msg += QString("#%1 fl:%2%3%4%5%6 ")
00946                            .arg(info->current_picture->temporal_reference)
00947                            .arg(info->current_picture->nb_fields)
00948                            .arg(coding_type)
00949                            .arg(top_bottom)
00950                            .arg(progressive)
00951                            .arg(info->current_picture->flags >> 4, 0, 16);
00952         }
00953         msg += QString("pos: %1").arg(vf->pkt.pos);
00954         LOG(VB_DECODE, LOG_INFO, msg);
00955     }
00956 
00957     return 0;
00958 }
00959 
00960 void MPEG2fixup::WriteFrame(QString filename, MPEG2frame *f)
00961 {
00962     MPEG2frame *tmpFrame = GetPoolFrame(f);
00963     if (tmpFrame == NULL)
00964         return;
00965     if (!tmpFrame->isSequence)
00966     {
00967         for (FrameList::Iterator it = vFrame.begin(); it != vFrame.end(); it++)
00968         {
00969             if ((*it)->isSequence)
00970             {
00971                 AddSequence(tmpFrame, *it);
00972                 break;
00973             }
00974         }
00975     }
00976     WriteFrame(filename, &tmpFrame->pkt);
00977     framePool.enqueue(tmpFrame);
00978 }
00979    
00980 void MPEG2fixup::WriteFrame(QString filename, AVPacket *pkt)
00981 {
00982     MPEG2frame *tmpFrame = GetPoolFrame(pkt);
00983     if (tmpFrame == NULL)
00984         return;
00985 
00986     QString fname = filename + ".enc";
00987     WriteData(fname, pkt->data, pkt->size);
00988 
00989     mpeg2dec_t *tmp_decoder = mpeg2_init();
00990     mpeg2_info_t *info = (mpeg2_info_t *)mpeg2_info(tmp_decoder);
00991 
00992     while (!info->display_picture)
00993     {
00994         if (ProcessVideo(tmpFrame, tmp_decoder))
00995         {
00996             delete tmpFrame;
00997             return;
00998         }
00999     }
01000 
01001     WriteYUV(filename, info);
01002     framePool.enqueue(tmpFrame);
01003     mpeg2_close(tmp_decoder);
01004 }
01005 
01006 void MPEG2fixup::WriteYUV(QString filename, const mpeg2_info_t *info)
01007 {
01008     int fh = open(filename.toLocal8Bit().constData(),
01009                   O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
01010     if (fh == -1) {
01011         LOG(VB_GENERAL, LOG_ERR,
01012             QString("Couldn't open file %1: ").arg(filename) + ENO);
01013         return;
01014     }
01015 
01016     int ret = write(fh, info->display_fbuf->buf[0],
01017                     info->sequence->width * info->sequence->height);
01018     if (ret < 0)
01019     {
01020         LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
01021                 ENO);
01022         goto closefd;
01023     }
01024     ret = write(fh, info->display_fbuf->buf[1],
01025                 info->sequence->chroma_width * info->sequence->chroma_height);
01026     if (ret < 0)
01027     {
01028         LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
01029                 ENO);
01030         goto closefd;
01031     }
01032     ret = write(fh, info->display_fbuf->buf[2],
01033                 info->sequence->chroma_width * info->sequence->chroma_height);
01034     if (ret < 0)
01035     {
01036         LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
01037                 ENO);
01038         goto closefd;
01039     }
01040 closefd:
01041     close(fh);
01042 }
01043 
01044 void MPEG2fixup::WriteData(QString filename, uint8_t *data, int size)
01045 {
01046     int fh = open(filename.toLocal8Bit().constData(),
01047                   O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
01048     if (fh == -1) {
01049         LOG(VB_GENERAL, LOG_ERR,
01050             QString("Couldn't open file %1: ").arg(filename) + ENO);
01051         return;
01052     }
01053 
01054     int ret = write(fh, data, size);
01055     if (ret < 0)
01056         LOG(VB_GENERAL, LOG_ERR, QString("write failed %1").arg(filename) +
01057                 ENO);
01058     close(fh);
01059 }
01060 
01061 extern "C" {
01062 #include "helper.h"
01063 }
01064 
01065 int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname)
01066 {
01067     const mpeg2_info_t *info;
01068     int outbuf_size;
01069     uint16_t intra_matrix[64] ATTR_ALIGN(16);
01070     AVFrame *picture;
01071     AVCodecContext *c = NULL;
01072     AVCodec *out_codec;
01073 
01074     info = mpeg2_info(img_decoder);
01075     if (!info->display_fbuf)
01076         return 1;
01077 
01078     outbuf_size = info->sequence->width * info->sequence->height * 2;
01079 
01080     if (!fname.isEmpty())
01081     {
01082         QString tmpstr = fname + ".yuv";
01083         WriteYUV(tmpstr, info);
01084     }
01085 
01086     picture = avcodec_alloc_frame();
01087 
01088     pkt->data = (uint8_t *)av_malloc(outbuf_size);
01089 
01090     picture->data[0] = info->display_fbuf->buf[0];
01091     picture->data[1] = info->display_fbuf->buf[1];
01092     picture->data[2] = info->display_fbuf->buf[2];
01093 
01094     picture->linesize[0] = info->sequence->width;
01095     picture->linesize[1] = info->sequence->chroma_width;
01096     picture->linesize[2] = info->sequence->chroma_width;
01097 
01098     picture->opaque = info->display_fbuf->id;
01099 
01100     copy_quant_matrix(img_decoder, intra_matrix);
01101 
01102     if (info->display_picture->nb_fields % 2)
01103         picture->top_field_first = !(info->display_picture->flags &
01104                                      PIC_FLAG_TOP_FIELD_FIRST);
01105     else
01106         picture->top_field_first = !!(info->display_picture->flags &
01107                                       PIC_FLAG_TOP_FIELD_FIRST);
01108 
01109     picture->interlaced_frame = !(info->display_picture->flags &
01110                                   PIC_FLAG_PROGRESSIVE_FRAME);
01111 
01112     out_codec = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO);
01113 
01114     if (!out_codec)
01115     {
01116         free(picture);
01117         LOG(VB_GENERAL, LOG_ERR, "Couldn't find MPEG2 encoder");
01118         return 1;
01119     }
01120 
01121     c = avcodec_alloc_context3(NULL);
01122 
01123     //We disable all optimizations for the time being.  There shouldn't be too
01124     //much encoding going on, and the optimizations have been shown to cause
01125     //corruption in some cases
01126     c->dsp_mask = 0xffff;
01127 
01128     //NOTE: The following may seem wrong, but avcodec requires
01129     //sequence->progressive == frame->progressive
01130     //We fix the discrepancy by discarding avcodec's sequence header, and
01131     //replace it with the original
01132     if (picture->interlaced_frame)
01133         c->flags |= CODEC_FLAG_INTERLACED_DCT;
01134 
01135     c->bit_rate = info->sequence->byte_rate << 3; //not used
01136     c->bit_rate_tolerance = c->bit_rate >> 2; //not used
01137     c->width = info->sequence->width;
01138     c->height = info->sequence->height;
01139     av_reduce(&c->time_base.num, &c->time_base.den,
01140               info->sequence->frame_period, 27000000LL, 100000);
01141     c->pix_fmt = PIX_FMT_YUV420P;
01142     c->max_b_frames = 0;
01143     c->has_b_frames = 0;
01144     c->rc_buffer_aggressivity = 1;
01145     //  c->profile = vidCC->profile;
01146     //  c->level = vidCC->level;
01147     c->rc_buffer_size = 0;
01148     c->gop_size = 0; // this should force all i-frames
01149     //  c->flags=CODEC_FLAG_LOW_DELAY;
01150 
01151     if (intra_matrix[0] == 0x08)
01152         c->intra_matrix = intra_matrix;
01153 
01154     c->qmin = c->qmax = 2;
01155 
01156     picture->pts = AV_NOPTS_VALUE;
01157     picture->key_frame = 1;
01158     picture->pict_type = AV_PICTURE_TYPE_NONE;
01159     picture->type = 0;
01160     picture->quality = 0;
01161 
01162     if (avcodec_open2(c, out_codec, NULL) < 0)
01163     {
01164         free(picture);
01165         LOG(VB_GENERAL, LOG_ERR, "could not open codec");
01166         return 1;
01167     }
01168 
01169     int got_packet = 0;
01170 
01171     int ret = avcodec_encode_video2(c, pkt, picture, &got_packet);
01172 
01173     if (ret < 0 || !got_packet)
01174     {
01175         free(picture);
01176         LOG(VB_GENERAL, LOG_ERR,
01177             QString("avcodec_encode_video failed (%1)").arg(pkt->size));
01178         return 1;
01179     }
01180 
01181     if (!fname.isEmpty())
01182     {
01183         QString ename = fname + ".enc";
01184         WriteData(ename, pkt->data, pkt->size);
01185 
01186         QString yname = fname + ".enc.yuv";
01187         WriteFrame(yname, pkt);
01188     }
01189     int delta = FindMPEG2Header(pkt->data, pkt->size, 0x00);
01190     //  out_size=avcodec_encode_video(c, outbuf, outbuf_size, picture);
01191     pkt->size -= delta; // a hack to get to the picture frame
01192     memmove(pkt->data, pkt->data + delta, pkt->size);
01193     SetRepeat(pkt->data, pkt->size, info->display_picture->nb_fields,
01194                !!(info->display_picture->flags & PIC_FLAG_TOP_FIELD_FIRST));
01195 
01196     avcodec_close(c);
01197     av_freep(&c);
01198     av_freep(&picture);
01199 
01200     return 0;
01201 }
01202 
01203 #define MAX_FRAMES 2000
01204 MPEG2frame *MPEG2fixup::GetPoolFrame(AVPacket *pkt)
01205 {
01206     MPEG2frame *f;
01207     static int frame_count = 0;
01208 
01209     if (framePool.isEmpty())
01210     {
01211         if (frame_count >= MAX_FRAMES)
01212         {
01213             LOG(VB_GENERAL, LOG_ERR, "No more queue slots!");
01214             return NULL;
01215         }
01216         f = new MPEG2frame(pkt->size);
01217         frame_count++;
01218     }
01219     else
01220         f = framePool.dequeue();
01221 
01222     f->set_pkt(pkt);
01223 
01224     return f;
01225 }
01226 
01227 MPEG2frame *MPEG2fixup::GetPoolFrame(MPEG2frame *f)
01228 {
01229     MPEG2frame *tmpFrame = GetPoolFrame(&f->pkt);
01230     if (!tmpFrame)
01231         return tmpFrame;
01232 
01233     tmpFrame->isSequence = f->isSequence;
01234     tmpFrame->isGop      = f->isGop;
01235     tmpFrame->mpeg2_seq  = f->mpeg2_seq;
01236     tmpFrame->mpeg2_gop  = f->mpeg2_gop;
01237     tmpFrame->mpeg2_pic  = f->mpeg2_pic;
01238     return tmpFrame;
01239 }
01240 
01241 int MPEG2fixup::GetFrame(AVPacket *pkt)
01242 {
01243     int ret;
01244 
01245     while (true)
01246     {
01247         bool done = false;
01248         if (unreadFrames.count())
01249         {
01250             vFrame.append(unreadFrames.dequeue());
01251             if (real_file_end && !unreadFrames.count())
01252                 file_end = true;
01253             return file_end;
01254         }
01255 
01256         while (!done)
01257         {
01258             pkt->pts = AV_NOPTS_VALUE;
01259             pkt->dts = AV_NOPTS_VALUE;
01260             ret = av_read_frame(inputFC, pkt);
01261 
01262             if (ret < 0)
01263             {
01264                 // If it is EAGAIN, obey it, dangit!
01265                 if (ret == -EAGAIN)
01266                     continue;
01267 
01268                 //insert a bogus frame (this won't be written out)
01269                 if (vFrame.isEmpty())
01270                 {
01271                     LOG(VB_GENERAL, LOG_ERR,
01272                         "Found end of file without finding any frames");
01273                     return 1;
01274                 }
01275 
01276                 MPEG2frame *tmpFrame = GetPoolFrame(&vFrame.last()->pkt);
01277                 if (tmpFrame == NULL)
01278                     return 1;
01279 
01280                 vFrame.append(tmpFrame);
01281                 real_file_end = true;
01282                 file_end = true;
01283                 return 1;
01284             }
01285 
01286             if (pkt->stream_index == vid_id ||
01287                   aFrame.contains(pkt->stream_index))
01288                 done = true;
01289             else 
01290                 av_free_packet(pkt);
01291         }
01292         pkt->duration = framenum++;
01293         if ((showprogress || update_status) &&
01294             QDateTime::currentDateTime() > statustime)
01295         {
01296             float percent_done = 100.0 * pkt->pos / filesize;
01297             if (update_status)
01298                 update_status(percent_done);
01299             if (showprogress)
01300                 LOG(VB_GENERAL, LOG_INFO, QString("%1% complete")
01301                         .arg(percent_done, 0, 'f', 1));
01302             if (check_abort && check_abort())
01303                 return REENCODE_STOPPED;
01304             statustime = QDateTime::currentDateTime();
01305             statustime = statustime.addSecs(status_update_time);
01306         }
01307 
01308 #ifdef DEBUG_AUDIO
01309         LOG(VB_DECODE, LOG_INFO, QString("Stream: %1 PTS: %2 DTS: %3 pos: %4")
01310               .arg(pkt->stream_index)
01311               .arg((pkt->pts == AV_NOPTS_VALUE) ? "NONE" : PtsTime(pkt->pts))
01312               .arg((pkt->dts == AV_NOPTS_VALUE) ? "NONE" : PtsTime(pkt->dts))
01313               .arg(pkt->pos));
01314 #endif
01315 
01316         MPEG2frame *tmpFrame = GetPoolFrame(pkt);
01317         if (tmpFrame == NULL)
01318             return 1;
01319 
01320         switch (inputFC->streams[pkt->stream_index]->codec->codec_type)
01321         {
01322             case AVMEDIA_TYPE_VIDEO:
01323                 vFrame.append(tmpFrame);
01324                 av_free_packet(pkt);
01325 
01326                 if (!ProcessVideo(vFrame.last(), header_decoder))
01327                     return 0;
01328                 framePool.enqueue(vFrame.takeLast());
01329                 break;
01330 
01331             case AVMEDIA_TYPE_AUDIO:
01332                 aFrame[pkt->stream_index]->append(tmpFrame);
01333                 av_free_packet(pkt);
01334                 return 0;
01335 
01336             default:
01337                 framePool.enqueue(tmpFrame);
01338                 av_free_packet(pkt);
01339                 return 1;
01340         }
01341     }
01342 }
01343 
01344 bool MPEG2fixup::FindStart()
01345 {
01346     AVPacket pkt;
01347     QMap <int, bool> found;
01348 
01349     av_init_packet(&pkt);
01350 
01351     do
01352     {
01353         if (GetFrame(&pkt))
01354             return false;
01355 
01356         if (vid_id == pkt.stream_index)
01357         {
01358             while (!vFrame.isEmpty())
01359             {
01360                 if (vFrame.first()->isSequence)
01361                 {
01362                     if (pkt.pos != vFrame.first()->pkt.pos)
01363                         break;
01364 
01365                     if ((uint64_t)pkt.pts != AV_NOPTS_VALUE ||
01366                         (uint64_t)pkt.dts != AV_NOPTS_VALUE)
01367                     {
01368                         if ((uint64_t)pkt.pts == AV_NOPTS_VALUE)
01369                             vFrame.first()->pkt.pts = pkt.dts;
01370 
01371                         LOG(VB_PROCESS, LOG_INFO,
01372                             "Found 1st valid video frame");
01373                         break;
01374                     }
01375                 }
01376 
01377                 LOG(VB_PROCESS, LOG_INFO, "Dropping V packet");
01378 
01379                 framePool.enqueue(vFrame.takeFirst());
01380             }
01381         }
01382 
01383         if (vFrame.isEmpty())
01384             continue;
01385 
01386         for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
01387         {
01388             if (found.contains(it.key()))
01389                 continue;
01390 
01391             FrameList *af = (*it);
01392 
01393             while (!af->isEmpty())
01394             {
01395                 int64_t delta = diff2x33(af->first()->pkt.pts,
01396                                          vFrame.first()->pkt.pts);
01397                 if (delta < -180000 || delta > 180000) //2 seconds
01398                 {
01399                     //Check all video sequence packets against current
01400                     //audio packet
01401                     MPEG2frame *foundframe = NULL;
01402                     for (FrameList::Iterator it2 = vFrame.begin();
01403                          it2 != vFrame.end(); it2++)
01404                     {
01405                         MPEG2frame *currFrame = (*it2);
01406                         if (currFrame->isSequence)
01407                         {
01408                             int64_t dlta1 = diff2x33(af->first()->pkt.pts,
01409                                                      currFrame->pkt.pts);
01410                             if (dlta1 >= -180000 && dlta1 <= 180000)
01411                             {
01412                                 foundframe = currFrame;
01413                                 delta = dlta1;
01414                                 break;
01415                             }
01416                         }
01417                     }
01418 
01419                     while (foundframe && vFrame.first() != foundframe)
01420                     {
01421                         framePool.enqueue(vFrame.takeFirst());
01422                     }
01423                 }
01424 
01425                 if (delta < -180000 || delta > 180000) //2 seconds
01426                 {
01427                     LOG(VB_PROCESS, LOG_INFO,
01428                         QString("Dropping A packet from stream %1")
01429                                    .arg(it.key()));
01430                     LOG(VB_PROCESS, LOG_INFO, QString("     A:%1 V:%2")
01431                             .arg(PtsTime(af->first()->pkt.pts))
01432                             .arg(PtsTime(vFrame.first()->pkt.pts)));
01433                     framePool.enqueue(af->takeFirst());
01434                     continue;
01435                 }
01436 
01437                 if (delta < 0 && af->count() > 1)
01438                 {
01439                     if (cmp2x33(af->at(1)->pkt.pts,
01440                                 vFrame.first()->pkt.pts) > 0)
01441                     {
01442                         LOG(VB_PROCESS, LOG_INFO,
01443                             QString("Found useful audio frame from stream %1")
01444                                 .arg(it.key()));
01445                         found[it.key()] = 1;
01446                         break;
01447                     }
01448                     else
01449                     {
01450                         LOG(VB_PROCESS, LOG_INFO,
01451                             QString("Dropping A packet from stream %1")
01452                                 .arg(it.key()));
01453                         framePool.enqueue(af->takeFirst());
01454                         continue;
01455                     }
01456                 }
01457                 else if (delta >= 0)
01458                 {
01459                     LOG(VB_PROCESS, LOG_INFO,
01460                         QString("Found useful audio frame from stream %1")
01461                             .arg(it.key()));
01462                     found[it.key()] = 1;
01463                     break;
01464                 }
01465 
01466                 if (af->count() == 1)
01467                     break;
01468             }
01469         }
01470     } while (found.count() != aFrame.count());
01471 
01472     return true;
01473 }
01474 
01475 void MPEG2fixup::SetRepeat(MPEG2frame *vf, int fields, bool topff)
01476 {
01477     vf->mpeg2_pic.nb_fields = 2;
01478     SetRepeat(vf->framePos, vf->pkt.data + vf->pkt.size - vf->framePos,
01479                fields, topff);
01480 }
01481 
01482 void MPEG2fixup::SetRepeat(uint8_t *ptr, int size, int fields, bool topff)
01483 {
01484     uint8_t *end = ptr + size;
01485     uint8_t setmask = 0x00;
01486     uint8_t clrmask = 0xff;
01487     if (topff)
01488         setmask |= 0x80;
01489     else
01490         clrmask &= 0x7f;
01491 
01492     if (fields == 2)
01493         clrmask &= 0xfd;
01494     else
01495         setmask |= 0x02;
01496 
01497     while (ptr < end)
01498     {
01499         if (MATCH_HEADER(ptr) && ptr[3] == 0xB5 && (ptr[4] & 0xF0) == 0x80)
01500         {
01501             //unset repeat_first_field
01502             //set top_field_first
01503             ptr[7] |= setmask;
01504             ptr[7] &= clrmask;
01505             return;
01506         }
01507 
01508         ptr++;
01509     }
01510 }
01511 
01512 MPEG2frame *MPEG2fixup::FindFrameNum(int frameNum)
01513 {
01514     for (FrameList::Iterator it = vFrame.begin(); it != vFrame.end(); it++)
01515     {
01516         if (GetFrameNum((*it)) == frameNum)
01517             return (*it);
01518     }
01519 
01520     return NULL;
01521 }
01522 
01523 void MPEG2fixup::RenumberFrames(int start_pos, int delta)
01524 {
01525     int maxPos = vFrame.count();
01526     
01527     for (int pos = start_pos; pos < maxPos; pos++)
01528     {
01529         MPEG2frame *frame = vFrame.at(pos);
01530         SetFrameNum(frame->framePos, GetFrameNum(frame) + delta);
01531         frame->mpeg2_pic.temporal_reference += delta;
01532     }
01533 }
01534 
01535 void MPEG2fixup::StoreSecondary()
01536 {
01537     while (vSecondary.count())
01538     {
01539         framePool.enqueue(vSecondary.takeFirst());
01540     }
01541 
01542     while (vFrame.count() > 1)
01543     {
01544         if (use_secondary && GetFrameTypeT(vFrame.first()) != 'B')
01545             vSecondary.append(vFrame.takeFirst());
01546         else
01547             framePool.enqueue(vFrame.takeFirst());
01548     }
01549 }
01550 
01551 int MPEG2fixup::PlaybackSecondary()
01552 {
01553     int frame_num = 0;
01554     mpeg2_reset(img_decoder, 1);
01555     for (FrameList::Iterator it = vSecondary.begin(); it != vSecondary.end();
01556          it++)
01557     {
01558         SetFrameNum((*it)->framePos, frame_num++);
01559         if (ProcessVideo((*it), img_decoder) < 0)
01560             return 1;
01561     }
01562     return 0;
01563 }
01564 
01565 MPEG2frame *MPEG2fixup::DecodeToFrame(int frameNum, int skip_reset)
01566 {
01567     MPEG2frame *spare = NULL;
01568     int found = 0;
01569     bool skip_first = false;
01570     const mpeg2_info_t * info = mpeg2_info(img_decoder);
01571     int maxPos = vFrame.count() - 1;
01572 
01573     if (vFrame.at(displayFrame)->isSequence)
01574     {
01575         skip_first = true;
01576         if (!skip_reset && (displayFrame != maxPos || displayFrame == 0))
01577             mpeg2_reset(img_decoder, 1);
01578     }
01579 
01580     spare = FindFrameNum(frameNum);
01581     if (!spare)
01582         return NULL;
01583 
01584     int framePos = vFrame.indexOf(spare);
01585 
01586     for (int curPos = displayFrame; displayFrame != maxPos;
01587          curPos++, displayFrame++)
01588     {
01589         if (ProcessVideo(vFrame.at(displayFrame), img_decoder) < 0)
01590             return NULL;
01591 
01592         if (!skip_first && curPos >= framePos && info->display_picture &&
01593             (int)info->display_picture->temporal_reference >= frameNum)
01594         {
01595             found = 1;
01596             displayFrame++;
01597             break;
01598         }
01599 
01600         skip_first = false;
01601     }
01602 
01603     if (!found)
01604     {
01605         int tmpFrameNum = frameNum;
01606         MPEG2frame *tmpFrame = GetPoolFrame(&spare->pkt);
01607         if (tmpFrame == NULL)
01608             return NULL;
01609 
01610         tmpFrame->framePos = tmpFrame->pkt.data +
01611                              (spare->framePos - spare->pkt.data);
01612 
01613         while (!info->display_picture ||
01614                (int)info->display_picture->temporal_reference < frameNum)
01615         {
01616             SetFrameNum(tmpFrame->framePos, ++tmpFrameNum);
01617             if (ProcessVideo(tmpFrame, img_decoder) < 0)
01618                 return NULL;
01619         }
01620 
01621         framePool.enqueue(tmpFrame);
01622     }
01623 
01624     if ((int)info->display_picture->temporal_reference > frameNum)
01625     {
01626         // the frame in question doesn't exist.  We have no idea where we are.
01627         // reset the displayFrame so we start searching from the beginning next
01628         // time
01629         displayFrame = 0;
01630         LOG(VB_GENERAL, LOG_NOTICE,
01631             QString("Frame %1 > %2.  Corruption likely at pos: %3")
01632                .arg(info->display_picture->temporal_reference)
01633                .arg(frameNum).arg(spare->pkt.pos));
01634     }
01635 
01636     return spare;
01637 }
01638 
01639 int MPEG2fixup::ConvertToI(FrameList *orderedFrames, int headPos)
01640 {
01641     MPEG2frame *spare = NULL;
01642     AVPacket pkt;
01643 #ifdef SPEW_FILES
01644     static int ins_count = 0;
01645 #endif
01646 
01647     //head_pos == 0 means that we are decoding B frames after a seq_header
01648     if (headPos == 0)
01649         if (PlaybackSecondary())
01650             return 1;
01651 
01652     for (FrameList::Iterator it = orderedFrames->begin(); 
01653          it != orderedFrames->end(); it++)
01654     {
01655         int i = GetFrameNum((*it));
01656         if ((spare = DecodeToFrame(i, headPos == 0)) == NULL)
01657             return 1;
01658 
01659         if (GetFrameTypeT(spare) == 'I')
01660             continue;
01661         
01662         pkt = spare->pkt;
01663         //pkt.data is a newly malloced area
01664 
01665         {
01666             QString fname;
01667 
01668 #ifdef SPEW_FILES
01669             if (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY))
01670                 fname = QString("cnv%1").arg(ins_count++);
01671 #endif
01672 
01673             if (BuildFrame(&pkt, fname))
01674                 return 1;
01675 
01676             LOG(VB_GENERAL, LOG_INFO,
01677                 QString("Converting frame #%1 from %2 to I %3")
01678                     .arg(i).arg(GetFrameTypeT(spare)).arg(fname));
01679         }
01680 
01681         spare->set_pkt(&pkt);
01682         av_free(pkt.data);
01683         SetFrameNum(spare->pkt.data, GetFrameNum(spare));
01684         ProcessVideo(spare, header_decoder); //process this new frame
01685     }
01686 
01687     //reorder frames
01688     vFrame.move(headPos, headPos + orderedFrames->count() - 1);
01689     return 0;
01690 }
01691 
01692 int MPEG2fixup::InsertFrame(int frameNum, int64_t deltaPTS,
01693                             int64_t ptsIncrement, int64_t initPTS)
01694 {
01695     MPEG2frame *spare = NULL;
01696     AVPacket pkt;
01697     int increment = 0;
01698     int index = 0;
01699 #ifdef SPEW_FILES
01700     static int ins_count = 0;
01701 #endif
01702 
01703     if ((spare = DecodeToFrame(frameNum, 0)) == NULL)
01704         return -1;
01705 
01706     pkt = spare->pkt;
01707     //pkt.data is a newly malloced area
01708 
01709     {
01710         QString fname;
01711 #if SPEW_FILES
01712         fname = (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY) ?
01713                 (QString("ins%1").arg(ins_count++)) : QString());
01714 #endif
01715 
01716         if (BuildFrame(&pkt, fname))
01717             return -1;
01718 
01719         LOG(VB_GENERAL, LOG_INFO,
01720             QString("Inserting %1 I-Frames after #%2 %3")
01721                 .arg((int)(deltaPTS / ptsIncrement))
01722                 .arg(GetFrameNum(spare)).arg(fname));
01723     }
01724     
01725     inc2x33(&pkt.pts, ptsIncrement * GetNbFields(spare) / 2 + initPTS);
01726 
01727     index = vFrame.indexOf(spare);
01728     while (index < vFrame.count() - 1 &&
01729            GetFrameTypeT(vFrame.at(index)) == 'B')
01730         spare = vFrame.at(index++);
01731 
01732     index = vFrame.indexOf(spare);
01733 
01734     while (deltaPTS > 0)
01735     {
01736         MPEG2frame *tmpFrame;
01737         index++;
01738         increment++;
01739         pkt.dts = pkt.pts;
01740         SetFrameNum(pkt.data, ++frameNum);
01741         tmpFrame = GetPoolFrame(&pkt);
01742         if (tmpFrame == NULL)
01743             return -1;
01744         vFrame.insert(index, tmpFrame);
01745         ProcessVideo(tmpFrame, header_decoder); //process new frame
01746 
01747         inc2x33(&pkt.pts, ptsIncrement);
01748         deltaPTS -= ptsIncrement;
01749     }
01750 
01751     av_free(pkt.data);
01752 
01753     // update frame # for all frames in this group
01754     RenumberFrames(index, increment);
01755 
01756     return increment;
01757 }
01758 
01759 void MPEG2fixup::AddRangeList(QStringList rangelist, int type)
01760 {
01761     QStringList::iterator i;
01762     frm_dir_map_t *mapPtr;
01763 
01764     if (type == MPF_TYPE_CUTLIST)
01765     {
01766         mapPtr = &delMap;
01767         discard = 0;
01768     }
01769     else
01770         mapPtr = &saveMap;
01771 
01772     mapPtr->clear();
01773 
01774     for (i = rangelist.begin(); i != rangelist.end(); ++i)
01775     {
01776         QStringList tmp = (*i).split(" - ");
01777         if (tmp.size() < 2)
01778             continue;
01779 
01780         bool ok[2] = { false, false };
01781 
01782         long long start = tmp[0].toLongLong(&ok[0]);
01783         long long end   = tmp[1].toLongLong(&ok[1]);
01784     
01785         if (ok[0] && ok[1])
01786         {
01787             if (start == 0)
01788             {
01789                 if (type == MPF_TYPE_CUTLIST)
01790                     discard = 1;
01791             }
01792             else
01793                 mapPtr->insert(start - 1, MARK_CUT_START);
01794 
01795             mapPtr->insert(end, MARK_CUT_END);
01796         }
01797     }
01798 
01799     if (rangelist.count())
01800         use_secondary = true;
01801 }
01802 
01803 void MPEG2fixup::ShowRangeMap(frm_dir_map_t *mapPtr, QString msg)
01804 {
01805     if (mapPtr->count())
01806     {
01807         int64_t start = 0;
01808         frm_dir_map_t::iterator it = mapPtr->begin();
01809         for (; it != mapPtr->end(); ++it)
01810             if (*it == 0)
01811                 msg += QString("\n\t\t%1 - %2").arg(start).arg(it.key());
01812             else
01813                 start = it.key();
01814         LOG(VB_PROCESS, LOG_INFO, msg);
01815     }
01816 }
01817 
01818 FrameList MPEG2fixup::ReorderDTStoPTS(FrameList *dtsOrder, int pos)
01819 {
01820     FrameList Lreorder;
01821     int maxPos = dtsOrder->count() - 1;
01822 
01823     if (pos >= maxPos)
01824         return Lreorder;
01825 
01826     MPEG2frame *frame = dtsOrder->at(pos);
01827 
01828     for (pos++; pos < maxPos && GetFrameTypeT(dtsOrder->at(pos)) == 'B'; pos++)
01829         Lreorder.append(dtsOrder->at(pos));
01830 
01831     Lreorder.append(frame);
01832     return Lreorder;
01833 }
01834 
01835 void MPEG2fixup::InitialPTSFixup(MPEG2frame *curFrame, int64_t &origvPTS,
01836                                  int64_t &PTSdiscrep, int numframes, bool fix)
01837 {
01838     int64_t tmpPTS = diff2x33(curFrame->pkt.pts,
01839                               origvPTS / 300);
01840 
01841     if ((uint64_t)curFrame->pkt.pts == AV_NOPTS_VALUE)
01842     {
01843         LOG(VB_PROCESS, LOG_INFO,
01844             QString("Found frame %1 with missing PTS at %2")
01845                 .arg(GetFrameNum(curFrame))
01846                 .arg(PtsTime(origvPTS / 300)));
01847         if (fix)
01848             curFrame->pkt.pts = origvPTS / 300;
01849         else
01850             PTSdiscrep = AV_NOPTS_VALUE;
01851     }
01852     else if (tmpPTS < -ptsIncrement ||
01853              tmpPTS > ptsIncrement*numframes)
01854     {
01855         if (tmpPTS != PTSdiscrep)
01856         {
01857             PTSdiscrep = tmpPTS;
01858             LOG(VB_PROCESS, LOG_INFO,
01859                 QString("Found invalid PTS (off by %1) at %2")
01860                        .arg(PtsTime(tmpPTS))
01861                        .arg(PtsTime(origvPTS / 300)));
01862         }
01863         if (fix)
01864             curFrame->pkt.pts = origvPTS / 300;
01865     }
01866     else
01867     {
01868         origvPTS = curFrame->pkt.pts * 300;
01869     }
01870     ptsinc((uint64_t *)&origvPTS,
01871             (uint64_t)(150 * ptsIncrement * GetNbFields(curFrame)));
01872 }
01873 
01874 void MPEG2fixup::dumpList(FrameList *list)
01875 {
01876     LOG(VB_GENERAL, LOG_INFO, "=========================================");
01877     LOG(VB_GENERAL, LOG_INFO, QString("List contains %1 items")
01878             .arg(list->count()));
01879 
01880      for (FrameList::Iterator it = list->begin(); it != list->end(); it++)
01881     {
01882         MPEG2frame *curFrame = (*it);
01883 
01884         LOG(VB_GENERAL, LOG_INFO,
01885             QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 pos: %6")
01886                 .arg(GetFrameTypeT(curFrame))
01887                 .arg(GetFrameNum(curFrame))
01888                 .arg(GetNbFields(curFrame))
01889                 .arg(PtsTime(curFrame->pkt.pts))
01890                 .arg(PtsTime(curFrame->pkt.dts))
01891                 .arg(curFrame->pkt.pos));
01892     }
01893     LOG(VB_GENERAL, LOG_INFO, "=========================================");
01894 }
01895 
01896 int MPEG2fixup::Start()
01897 {
01898     // NOTE: expectedvPTS/DTS are in units of SCR (300*PTS) to allow for better
01899     // accounting of rounding errors (still won't be right, but better)
01900     int64_t expectedvPTS, expectedPTS[N_AUDIO];
01901     int64_t expectedDTS = 0, lastPTS = 0, initPTS = 0, deltaPTS = 0;
01902     int64_t origvPTS = 0, origaPTS[N_AUDIO];
01903     int64_t cutStartPTS = 0, cutEndPTS = 0;
01904     uint64_t frame_count = 0;
01905     int new_discard_state = 0;
01906     int ret;
01907     QMap<int, int> af_dlta_cnt, cutState;
01908 
01909     AVPacket pkt, lastRealvPkt;
01910 
01911     if (!InitAV(infile, format, 0))
01912         return GENERIC_EXIT_NOT_OK;
01913 
01914     if (!FindStart())
01915         return GENERIC_EXIT_NOT_OK;
01916 
01917     av_init_packet(&pkt);
01918 
01919     ptsIncrement = vFrame.first()->mpeg2_seq.frame_period / 300;
01920 
01921     initPTS = vFrame.first()->pkt.pts;
01922 
01923     LOG(VB_GENERAL, LOG_INFO, QString("#%1 PTS:%2 Delta: 0.0ms queue: %3")
01924             .arg(vid_id).arg(PtsTime(vFrame.first()->pkt.pts))
01925             .arg(vFrame.count()));
01926 
01927     for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
01928     {
01929         FrameList *af = (*it);
01930         deltaPTS = diff2x33(vFrame.first()->pkt.pts, af->first()->pkt.pts);
01931         LOG(VB_GENERAL, LOG_INFO,
01932             QString("#%1 PTS:%2 Delta: %3ms queue: %4")
01933                 .arg(it.key()) .arg(PtsTime(af->first()->pkt.pts))
01934                 .arg(1000.0*deltaPTS / 90000.0).arg(af->count()));
01935 
01936         if (cmp2x33(af->first()->pkt.pts, initPTS) < 0)
01937             initPTS = af->first()->pkt.pts;
01938     }
01939 
01940     initPTS -= 16200; //0.18 seconds back to prevent underflow
01941 
01942     PTSOffsetQueue poq(vid_id, aFrame.keys(), initPTS);
01943 
01944     LOG(VB_PROCESS, LOG_INFO,
01945         QString("ptsIncrement: %1 Frame #: %2 PTS-adjust: %3")
01946             .arg(ptsIncrement).arg(GetFrameNum(vFrame.first()))
01947             .arg(PtsTime(initPTS)));
01948 
01949 
01950     origvPTS = 300 * udiff2x33(vFrame.first()->pkt.pts,
01951                      ptsIncrement * GetFrameNum(vFrame.first()));
01952     expectedvPTS = 300 * (udiff2x33(vFrame.first()->pkt.pts, initPTS) -
01953                          (ptsIncrement * GetFrameNum(vFrame.first())));
01954     expectedDTS = expectedvPTS - 300 * ptsIncrement;
01955 
01956     if (discard)
01957     {
01958         cutStartPTS = origvPTS / 300;
01959     }
01960 
01961     for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
01962     {
01963         FrameList *af = (*it);
01964         origaPTS[it.key()] = af->first()->pkt.pts * 300;
01965         expectedPTS[it.key()] = udiff2x33(af->first()->pkt.pts, initPTS);
01966         af_dlta_cnt[it.key()] = 0;
01967         cutState[it.key()] = !!(discard);
01968     }
01969 
01970     ShowRangeMap(&delMap, "Cutlist:");
01971     ShowRangeMap(&saveMap, "Same Range:");
01972 
01973     InitReplex();
01974 
01975     while (!file_end)
01976     {
01977         /* read packet */
01978         if ((ret = GetFrame(&pkt)) < 0)
01979             return ret;
01980 
01981         if (vFrame.count() && (file_end || vFrame.last()->isSequence))
01982         {
01983             displayFrame = 0;
01984 
01985             // since we might reorder the frames when coming out of a cutpoint
01986             // me need to save the first frame here, as it is guaranteed to
01987             // have a sequence header.
01988             MPEG2frame *seqFrame = vFrame.first();
01989 
01990             if (!seqFrame->isSequence)
01991             {
01992                 LOG(VB_GENERAL, LOG_WARNING, 
01993                     QString("Problem: Frame %1 (type %2) doesn't contain "
01994                             "sequence header!")
01995                        .arg(frame_count) .arg(GetFrameTypeT(seqFrame)));
01996             }
01997 
01998             if (ptsIncrement != seqFrame->mpeg2_seq.frame_period / 300)
01999             {
02000                 LOG(VB_GENERAL, LOG_WARNING,
02001                     QString("WARNING - Unsupported FPS change from %1 to %2")
02002                        .arg(90000.0 / ptsIncrement, 0, 'f', 2)
02003                        .arg(27000000.0 / seqFrame->mpeg2_seq.frame_period,
02004                             0, 'f', 2));
02005             }
02006 
02007             for (int frame_pos = 0; frame_pos < vFrame.count() - 1;)
02008             {
02009                 bool ptsorder_eq_dtsorder = false;
02010                 int64_t dtsExtra = 0, PTSdiscrep = 0;
02011                 FrameList Lreorder;
02012                 MPEG2frame *markedFrame = NULL, *markedFrameP = NULL;
02013 
02014                 if (expectedvPTS != expectedDTS + ptsIncrement * 300)
02015                 {
02016                     LOG(VB_GENERAL, LOG_ERR,
02017                         QString("expectedPTS != expectedDTS + ptsIncrement"));
02018                     LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3")
02019                             .arg(PtsTime(expectedvPTS / 300))
02020                             .arg(PtsTime(expectedDTS / 300))
02021                             .arg(PtsTime(ptsIncrement)));
02022                     LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3")
02023                             .arg(expectedvPTS)
02024                             .arg(expectedDTS)
02025                             .arg(ptsIncrement));
02026                     return GENERIC_EXIT_NOT_OK;
02027                 }
02028 
02029                 //reorder frames in presentation order (to the next I/P frame)
02030                 Lreorder = ReorderDTStoPTS(&vFrame, frame_pos);
02031 
02032                 //First pass at fixing PTS values (fixes gross errors only)
02033                 for (FrameList::Iterator it2 = Lreorder.begin();
02034                      it2 != Lreorder.end(); it2++)
02035                 {
02036                     MPEG2frame *curFrame = (*it2);
02037                     poq.UpdateOrigPTS(vid_id, origvPTS, curFrame->pkt);
02038                     InitialPTSFixup(curFrame, origvPTS, PTSdiscrep, 
02039                                     maxframes, true);
02040                 }
02041 
02042                 // if there was a PTS jump, find the largest change
02043                 // in the next x frames
02044                 // At the end of this, vFrame should look just like it did
02045                 // beforehand
02046                 if (PTSdiscrep && !file_end)
02047                 {
02048                     int pos = vFrame.count();
02049                     int count = Lreorder.count();
02050                     while (vFrame.count() - frame_pos - count < 20 && !file_end)
02051                         if ((ret = GetFrame(&pkt)) < 0)
02052                             return ret;
02053 
02054                     if (!file_end)
02055                     {
02056                         int64_t tmp_origvPTS = origvPTS;
02057                         int numframes = (maxframes > 1) ? maxframes - 1 : 1;
02058                         bool done = false;
02059                         while (!done &&
02060                                (frame_pos + count + 1) < vFrame.count())
02061                         {
02062                             FrameList tmpReorder;
02063                             tmpReorder = ReorderDTStoPTS(&vFrame,
02064                                                          frame_pos + count);
02065                             for (FrameList::Iterator it2 = tmpReorder.begin();
02066                                  it2 != tmpReorder.end(); it2++)
02067                             {
02068                                 MPEG2frame *curFrame = (*it2);
02069                                 int64_t tmpPTSdiscrep = 0;
02070                                 InitialPTSFixup(curFrame, tmp_origvPTS,
02071                                            tmpPTSdiscrep, numframes, false);
02072                                 if (!tmpPTSdiscrep)
02073                                 {
02074                                     //discrepancy was short-lived, continue on
02075                                     done = true;
02076                                     PTSdiscrep = 0;
02077                                     break;
02078                                 }
02079                                 if (tmpPTSdiscrep != (int64_t)AV_NOPTS_VALUE &&
02080                                     tmpPTSdiscrep != PTSdiscrep)
02081                                     PTSdiscrep = tmpPTSdiscrep;
02082                             }
02083                             count += tmpReorder.count();
02084                         }
02085                     }
02086 
02087                     // push extra read frames onto 'unreadFrames' queue
02088                     while (vFrame.count() > pos)
02089                     {
02090                         unreadFrames.enqueue(vFrame.takeAt(pos));
02091                     }
02092                     file_end = false;
02093                 }
02094   
02095                 //check for cutpoints and convert to I-frames if needed 
02096                 for (int curIndex = 0; curIndex < Lreorder.count(); curIndex++)
02097                 {
02098                     MPEG2frame *curFrame = Lreorder.at(curIndex);
02099                     if (saveMap.count())
02100                     {
02101                         if (saveMap.begin().key() <= frame_count)
02102                            saveMap.remove(saveMap.begin().key());
02103                         if (saveMap.count() && saveMap.begin().value() == 0)
02104                         {
02105                             LOG(VB_GENERAL, LOG_INFO,
02106                                 QString("Saving frame #%1") .arg(frame_count));
02107 
02108                             if (GetFrameTypeT(curFrame) != 'I' &&
02109                                 ConvertToI(&Lreorder, frame_pos))
02110                             {
02111                                 return GENERIC_EXIT_WRITE_FRAME_ERROR;
02112                             }
02113 
02114                             WriteFrame(QString("save%1.yuv").arg(frame_count),
02115                                        curFrame);
02116                         }
02117                     }
02118 
02119                     if (delMap.count() && delMap.begin().key() <= frame_count)
02120                     {
02121                         new_discard_state = delMap.begin().value();
02122                         LOG(VB_GENERAL, LOG_INFO,
02123                             QString("Del map found %1 at %2 (%3)")
02124                                 .arg(new_discard_state) .arg(frame_count)
02125                                 .arg(delMap.begin().key()));
02126 
02127                         delMap.remove(delMap.begin().key());
02128                         markedFrameP = curFrame;
02129 
02130                         if (!new_discard_state)
02131                         {
02132                             cutEndPTS = markedFrameP->pkt.pts;
02133                             poq.SetNextPTS(
02134                                       diff2x33(cutEndPTS, expectedvPTS / 300),
02135                                       cutEndPTS);
02136                         }
02137                         else
02138                         {
02139                             cutStartPTS =
02140                                   add2x33(markedFrameP->pkt.pts,
02141                                           ptsIncrement * 
02142                                           GetNbFields(markedFrameP) / 2);
02143                             for (FrameMap::Iterator it3 = aFrame.begin();
02144                                  it3 != aFrame.end(); it3++)
02145                             {
02146                                 cutState[it3.key()] = 1;
02147                             }
02148                         }
02149 
02150                         // Rebuild when 'B' frame, or completing a cut, and the
02151                         // marked frame is a 'P' frame.
02152                         // After conversion, frames will be in linear order.
02153                         if ((GetFrameTypeT(curFrame) == 'B') ||
02154                             (!new_discard_state &&
02155                              (GetFrameTypeT(curFrame) == 'P')))
02156                         {
02157                             if (ConvertToI(&Lreorder, frame_pos))
02158                                 return GENERIC_EXIT_WRITE_FRAME_ERROR;
02159                             ptsorder_eq_dtsorder = true;
02160                         }
02161                         else if (!new_discard_state &&
02162                                  GetFrameTypeT(curFrame) == 'I')
02163                         {
02164                             vFrame.move(frame_pos, frame_pos + curIndex);
02165                             ptsorder_eq_dtsorder = true;
02166                         }
02167 
02168                         //convert from presentation-order to decode-order
02169                         markedFrame = vFrame.at(frame_pos + curIndex);
02170 
02171                         if (!new_discard_state)
02172                         {
02173                             AddSequence(markedFrame, seqFrame);
02174                             RenumberFrames(frame_pos + curIndex,
02175                                            - GetFrameNum(markedFrame));
02176                         }
02177                     }
02178 
02179                     frame_count++;
02180                 }
02181 
02182                 if (!Lreorder.isEmpty())
02183                     lastRealvPkt = Lreorder.last()->pkt;
02184 
02185                 if (markedFrame || !discard)
02186                 {
02187                     //check for PTS discontinuity
02188                     for (FrameList::Iterator it2 = Lreorder.begin();
02189                          it2 != Lreorder.end(); it2++)
02190                     {
02191                         MPEG2frame *curFrame = (*it2);
02192                         if (markedFrameP && discard)
02193                         {
02194                             if (curFrame != markedFrameP)
02195                                 continue;
02196 
02197                             markedFrameP = NULL;
02198                         }
02199 
02200                         dec2x33(&curFrame->pkt.pts,
02201                                 poq.Get(vid_id, &curFrame->pkt));
02202                         deltaPTS = diff2x33(curFrame->pkt.pts,
02203                                             expectedvPTS / 300);
02204 
02205                         if (deltaPTS < -2 || deltaPTS > 2)
02206                         {
02207                             LOG(VB_PROCESS, LOG_INFO,
02208                                 QString("PTS discrepancy: %1 != %2 on "
02209                                         "%3-Type (%4)")
02210                                     .arg(curFrame->pkt.pts)
02211                                     .arg(expectedvPTS / 300)
02212                                     .arg(GetFrameTypeT(curFrame))
02213                                     .arg(GetFrameNum(curFrame)));
02214                         }
02215 
02216                         //remove repeat_first_field if necessary
02217                         if (no_repeat)
02218                             SetRepeat(curFrame, 2, 0);
02219 
02220                         //force PTS to stay in sync (this could be a bad idea!)
02221                         if (fix_PTS)
02222                             curFrame->pkt.pts = expectedvPTS / 300;
02223 
02224                         if (deltaPTS > ptsIncrement*maxframes)
02225                         {
02226                             LOG(VB_GENERAL, LOG_NOTICE,
02227                                 QString("Need to insert %1 frames > max "
02228                                         "allowed: %2.  Assuming bad PTS")
02229                                     .arg((int)(deltaPTS / ptsIncrement))
02230                                     .arg(maxframes));
02231                             curFrame->pkt.pts = expectedvPTS / 300;
02232                             deltaPTS = 0;
02233                         }
02234 
02235                         lastPTS = expectedvPTS;
02236                         expectedvPTS += 150 * ptsIncrement *
02237                                         GetNbFields(curFrame);
02238 
02239                         if (curFrame == markedFrameP && new_discard_state)
02240                             break;
02241                     }
02242 
02243                     // dtsExtra is applied at the end of this block if the
02244                     // current tail has repeat_first_field set
02245                     if (ptsorder_eq_dtsorder)
02246                         dtsExtra = 0;
02247                     else
02248                         dtsExtra = 150 * ptsIncrement *
02249                                    (GetNbFields(vFrame.at(frame_pos)) - 2);
02250 
02251                     if (!markedFrame && deltaPTS > (4 * ptsIncrement / 5))
02252                     {
02253                         // if we are off by more than 1/2 frame, it is time to
02254                         // add a frame
02255                         // The frame(s) will be added right after lVpkt_tail,
02256                         // and lVpkt_head will be adjusted accordingly
02257 
02258                         vFrame.at(frame_pos)->pkt.pts = lastPTS / 300;
02259                         int ret = InsertFrame(GetFrameNum(vFrame.at(frame_pos)),
02260                                               deltaPTS, ptsIncrement, 0);
02261                         
02262                         if (ret < 0)
02263                             return GENERIC_EXIT_WRITE_FRAME_ERROR;
02264 
02265                         for (int index = frame_pos + Lreorder.count();
02266                              ret && index < vFrame.count(); index++, --ret)
02267                         {
02268                             lastPTS = expectedvPTS;
02269                             expectedvPTS += 150 * ptsIncrement *
02270                                             GetNbFields(vFrame.at(index));
02271                             Lreorder.append(vFrame.at(index));
02272                         }
02273                     }
02274 
02275                     // Set DTS (ignore any current values), and send frame to
02276                     // multiplexer
02277 
02278                     for (int i = 0; i < Lreorder.count(); i++, frame_pos++)
02279                     {
02280                         MPEG2frame *curFrame = vFrame.at(frame_pos);
02281                         if (discard)
02282                         {
02283                             if (curFrame != markedFrame)
02284                                 continue;
02285 
02286                             discard = false;
02287                             markedFrame = NULL;
02288                         }
02289 
02290                         curFrame->pkt.dts = (expectedDTS / 300);
02291 #if 0
02292                         if (GetFrameTypeT(curFrame) == 'B')
02293                             curFrame->pkt.pts = (expectedDTS / 300);
02294 #endif
02295                         expectedDTS += 150 * ptsIncrement *
02296                                        ((!ptsorder_eq_dtsorder && i == 0) ?  2 :
02297                                         GetNbFields(curFrame));
02298                         LOG(VB_FRAME, LOG_INFO,
02299                             QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 "
02300                                     "pos: %6")
02301                                 .arg(GetFrameTypeT(curFrame))
02302                                 .arg(GetFrameNum(curFrame))
02303                                 .arg(GetNbFields(curFrame))
02304                                 .arg(PtsTime(curFrame->pkt.pts))
02305                                 .arg(PtsTime(curFrame->pkt.dts))
02306                                 .arg(curFrame->pkt.pos));
02307                         if (AddFrame(curFrame))
02308                             return GENERIC_EXIT_DEADLOCK;
02309 
02310                         if (curFrame == markedFrame)
02311                         {
02312                             markedFrame = NULL;
02313                             discard = true;
02314                         }
02315                     }
02316                         
02317                     expectedDTS += dtsExtra;
02318                 }
02319                 else
02320                 {
02321                     frame_pos += Lreorder.count();
02322                 }
02323                 if (PTSdiscrep)
02324                     poq.SetNextPos(add2x33(poq.Get(vid_id, &lastRealvPkt),
02325                                                    PTSdiscrep), lastRealvPkt);
02326             }
02327 
02328             if (discard)
02329                 cutEndPTS = lastRealvPkt.pts;
02330 
02331             if (file_end)
02332                 use_secondary = false;
02333             if (vFrame.count() > 1 || file_end)
02334                 StoreSecondary();
02335         }
02336 
02337         for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
02338         {
02339             FrameList *af = (*it);
02340             AVCodecContext *CC = getCodecContext(it.key());
02341             bool backwardsPTS = false;
02342 
02343             while (af->count())
02344             {
02345                 // What to do if the CC is corrupt?
02346                 // Just wait and hope it repairs itself
02347                 if (CC->sample_rate == 0 || CC->frame_size == 0)
02348                     break;
02349 
02350                 // The order of processing frames is critical to making
02351                 // everything work.  Backwards PTS discrepancies complicate
02352                 // the processing significantly
02353                 // Processing works as follows:
02354                 //   detect whether there is a discontinuous PTS (tmpPTS != 0)
02355                 //     in the audio stream only.
02356                 //   next check if a cutpoint is active, and discard frames
02357                 //     as needed
02358                 //   next check that the current PTS < last video PTS
02359                 //   if we get this far, update the expected PTS, and write out
02360                 //     the audio frame
02361                 int64_t nextPTS, tmpPTS;
02362                 int64_t incPTS =
02363                          90000LL * (int64_t)CC->frame_size / CC->sample_rate;
02364 
02365                 if (poq.UpdateOrigPTS(it.key(), origaPTS[it.key()],
02366                                                   af->first()->pkt) < 0)
02367                 {
02368                     backwardsPTS = true;
02369                     af_dlta_cnt[it.key()] = 0;
02370                 }
02371 
02372                 tmpPTS = diff2x33(af->first()->pkt.pts,
02373                                   origaPTS[it.key()] / 300);
02374 
02375                 if (tmpPTS < -incPTS)
02376                 {
02377 #ifdef DEBUG_AUDIO
02378                     LOG(VB_PROCESS, LOG_INFO,
02379                         QString("Aud discard: PTS %1 < %2")
02380                             .arg(PtsTime(af->first()->pkt.pts))
02381                             .arg(PtsTime(origaPTS[it.key()] / 300)));
02382 #endif
02383                     framePool.enqueue(af->takeFirst());
02384                     af_dlta_cnt[it.key()] = 0;
02385                     continue;
02386                 }
02387 
02388                 if (tmpPTS > incPTS * maxframes)
02389                 {
02390                     LOG(VB_PROCESS, LOG_INFO,
02391                         QString("Found invalid audio PTS (off by %1) at %2")
02392                             .arg(PtsTime(tmpPTS))
02393                             .arg(PtsTime(origaPTS[it.key()] / 300)));
02394                     if (backwardsPTS && tmpPTS < 90000LL)
02395                     {
02396                         //there are missing audio frames
02397                         LOG(VB_PROCESS, LOG_INFO,
02398                             "Fixing missing audio frames");
02399                         ptsinc((uint64_t *)&origaPTS[it.key()], 300 * tmpPTS);
02400                         backwardsPTS = false;
02401                     }
02402                     else if (tmpPTS < 90000LL * 4) // 4 seconds
02403                     {
02404                         if (af_dlta_cnt[it.key()] >= 20)
02405                         {
02406                             //If there are 20 consecutive frames with an
02407                             //offset < 4sec, assume a mismatch and correct.
02408                             //Note: if we allow too much discrepancy,
02409                             //we could overrun the video queue
02410                             ptsinc((uint64_t *)&origaPTS[it.key()],
02411                                    300 * tmpPTS);
02412                             af_dlta_cnt[it.key()] = 0;
02413                         }
02414                         else
02415                             af_dlta_cnt[it.key()]++;
02416                     }
02417                     af->first()->pkt.pts = origaPTS[it.key()] / 300;
02418                 }
02419                 else if (tmpPTS > incPTS) //correct for small discrepancies
02420                 {
02421                     incPTS += incPTS;
02422                     backwardsPTS = false;
02423                     af_dlta_cnt[it.key()] = 0;
02424                 }
02425                 else
02426                 {
02427                     backwardsPTS = false;
02428                     af_dlta_cnt[it.key()] = 0;
02429                 }
02430 
02431                 nextPTS = add2x33(af->first()->pkt.pts,
02432                            90000LL * (int64_t)CC->frame_size / CC->sample_rate);
02433 
02434                 if ((cutState[it.key()] == 1 &&
02435                      cmp2x33(nextPTS, cutStartPTS) > 0) ||
02436                     (cutState[it.key()] == 2 && 
02437                      cmp2x33(af->first()->pkt.pts, cutEndPTS) < 0))
02438                 {
02439 #ifdef DEBUG_AUDIO
02440                     LOG(VB_PROCESS, LOG_INFO,
02441                         QString("Aud in cutpoint: %1 > %2 && %3 < %4")
02442                             .arg(PtsTime(nextPTS)).arg(PtsTime(cutStartPTS))
02443                             .arg(PtsTime(af->first()->pkt.pts))
02444                             .arg(PtsTime(cutEndPTS)));
02445 #endif
02446                     framePool.enqueue(af->takeFirst());
02447                     cutState[it.key()] = 2;
02448                     ptsinc((uint64_t *)&origaPTS[it.key()], incPTS * 300);
02449                     continue;
02450                 }
02451 
02452                 int64_t deltaPTS = poq.Get(it.key(), &af->first()->pkt);
02453 
02454                 if (udiff2x33(nextPTS, deltaPTS) * 300 > expectedDTS &&
02455                     cutState[it.key()] != 1)
02456                 {
02457 #ifdef DEBUG_AUDIO
02458                     LOG(VB_PROCESS, LOG_INFO, QString("Aud not ready: %1 > %2")
02459                             .arg(PtsTime(udiff2x33(nextPTS, deltaPTS)))
02460                             .arg(PtsTime(expectedDTS / 300)));
02461 #endif
02462                     break;
02463                 }
02464 
02465                 if (cutState[it.key()] == 2)
02466                     cutState[it.key()] = 0;
02467 
02468                 ptsinc((uint64_t *)&origaPTS[it.key()], incPTS * 300);
02469 
02470                 dec2x33(&af->first()->pkt.pts, deltaPTS);
02471 
02472 #if 0
02473                 expectedPTS[it.key()] = udiff2x33(nextPTS, initPTS);
02474                 write_audio(lApkt_tail->pkt, initPTS);
02475 #endif
02476                 LOG(VB_FRAME, LOG_INFO, QString("AUD #%1: pts: %2 pos: %3")
02477                         .arg(it.key()) 
02478                         .arg(PtsTime(af->first()->pkt.pts))
02479                         .arg(af->first()->pkt.pos));
02480                 if (AddFrame(af->first()))
02481                     return GENERIC_EXIT_DEADLOCK;
02482                 framePool.enqueue(af->takeFirst());
02483             }
02484         }
02485     }
02486 
02487     rx.done = 1;
02488     pthread_mutex_lock( &rx.mutex );
02489     pthread_cond_signal(&rx.cond);
02490     pthread_mutex_unlock( &rx.mutex );
02491     pthread_join(thread, NULL);
02492 
02493     avformat_close_input(&inputFC);
02494     inputFC = NULL;
02495     return REENCODE_OK;
02496 }
02497 
02498 #ifdef NO_MYTH
02499 int verboseMask = VB_GENERAL;
02500 
02501 void usage(char *s)
02502 {
02503     fprintf(stderr, "%s usage:\n", s);
02504     fprintf(stderr, "\t--infile <file>    -i <file> : Input mpg file\n");
02505     fprintf(stderr, "\t--outfile <file>   -o <file> : Output mpg file\n");
02506     fprintf(stderr, "\t--dbg_lvl #        -d #      : Debug level\n");
02507     fprintf(stderr, "\t--maxframes #      -m #      : Max frames to insert at once (default=10)\n");
02508     fprintf(stderr, "\t--cutlist \"start - end\" -c : Apply a cutlist.  Specify on e'-c' per cut\n");
02509     fprintf(stderr, "\t--no3to2           -t        : Remove 3:2 pullup\n");
02510     fprintf(stderr, "\t--fixup            -f        : make PTS continuous\n");
02511     fprintf(stderr, "\t--ostream <dvd|ps> -e        : Output stream type (defaults to ps)\n");
02512     fprintf(stderr, "\t--showprogress     -p        : show progress\n");
02513     fprintf(stderr, "\t--help             -h        : This screen\n");
02514     exit(0);
02515 }
02516 
02517 int main(int argc, char **argv)
02518 {
02519     QStringList cutlist;
02520     QStringList savelist;
02521     char *infile = NULL, *outfile = NULL, *format = NULL;
02522     int no_repeat = 0, fix_PTS = 0, max_frames = 20, otype = REPLEX_MPEG2;
02523     bool showprogress = 0;
02524     const struct option long_options[] =
02525         {
02526             {"infile", required_argument, NULL, 'i'},
02527 
02528             {"outfile", required_argument, NULL, 'o'},
02529             {"format", required_argument, NULL, 'r'},
02530             {"dbg_lvl", required_argument, NULL, 'd'},
02531             {"cutlist", required_argument, NULL, 'c'},
02532             {"saveframe", required_argument, NULL, 's'},
02533             {"ostream", required_argument, NULL, 'e'},
02534             {"no3to2", no_argument, NULL, 't'},
02535             {"fixup", no_argument, NULL, 'f'},
02536             {"showprogress", no_argument, NULL, 'p'},
02537             {"help", no_argument , NULL, 'h'},
02538             {0, 0, 0, 0}
02539         };
02540 
02541     while (1)
02542     {
02543         int option_index = 0;
02544         char c;
02545         c = getopt_long (argc, argv, "i:o:d:r:m:c:s:e:tfph",
02546                          long_options, &option_index);
02547 
02548         if (c == -1)
02549             break;
02550 
02551         switch (c)
02552         {
02553 
02554             case 'i':
02555                 infile = optarg;
02556                 break;
02557 
02558             case 'o':
02559                 outfile = optarg;
02560                 break;
02561 
02562             case 'r':
02563                 format = optarg;
02564                 break;
02565 
02566             case 'e':
02567                 if (strlen(optarg) == 3 && strncmp(optarg, "dvd", 3) == 0)
02568                     otype = REPLEX_DVD;
02569                 break;
02570 
02571             case 'd':
02572                 verboseMask = atoi(optarg);
02573                 break;
02574 
02575             case 'm':
02576                 max_frames = atoi(optarg);
02577                 break;
02578 
02579             case 'c':
02580                 cutlist.append(optarg);
02581                 break;
02582 
02583             case 't':
02584                 no_repeat = 1;
02585 
02586             case 'f':
02587                 fix_PTS = 1;
02588                 break;
02589 
02590             case 's':
02591                 savelist.append(optarg);
02592                 break;
02593 
02594             case 'p':
02595                 showprogress = true;
02596                 break;
02597 
02598             case 'h':
02599 
02600             case '?':
02601 
02602             default:
02603                 usage(argv[0]);
02604         }
02605     }
02606 
02607     if (infile == NULL || outfile == NULL)
02608         usage(argv[0]);
02609 
02610     MPEG2fixup m2f(infile, outfile, NULL, format, 
02611                    no_repeat, fix_PTS, max_frames,
02612                    showprogress, otype);
02613 
02614     if (cutlist.count())
02615         m2f.AddRangeList(cutlist, MPF_TYPE_CUTLIST);
02616     if (savelist.count())
02617         m2f.AddRangeList(savelist, MPF_TYPE_SAVELIST);
02618     return m2f.Start();
02619 }
02620 #endif
02621 
02622 int MPEG2fixup::BuildKeyframeIndex(QString &file,
02623                                    frm_pos_map_t &posMap)
02624 {
02625     LOG(VB_GENERAL, LOG_INFO, "Generating Keyframe Index");
02626 
02627     AVPacket pkt;
02628     int count = 0;
02629 
02630     /*============ initialise AV ===============*/
02631     if (!InitAV(file, NULL, 0))
02632         return GENERIC_EXIT_NOT_OK;
02633 
02634     if (mkvfile)
02635     {
02636         LOG(VB_GENERAL, LOG_INFO, "Seek tables are not required for MKV");
02637         return GENERIC_EXIT_NOT_OK;
02638     }
02639 
02640     av_init_packet(&pkt);
02641 
02642     while (av_read_frame(inputFC, &pkt) >= 0)
02643     {
02644         if (pkt.stream_index == vid_id)
02645         {
02646             if (pkt.flags & AV_PKT_FLAG_KEY)
02647                 posMap[count] = pkt.pos;
02648             count++;
02649         }
02650         av_free_packet(&pkt);
02651     }
02652 
02653     // Close input file
02654     avformat_close_input(&inputFC);
02655     inputFC = NULL;
02656 
02657     LOG(VB_GENERAL, LOG_NOTICE, "Transcode Completed");
02658 
02659     return REENCODE_OK;
02660 }
02661 
02662 /*
02663  * vim:ts=4:sw=4:ai:et:si:sts=4
02664  */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends