|
MythTV
0.26-pre
|
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 */
1.7.6.1