00001
00002 #include <cerrno>
00003 #include <cassert>
00004 #include <cstring>
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include <unistd.h>
00008 #include <pthread.h>
00009
00010
00011 #include <iostream>
00012 using namespace std;
00013
00014
00015 #include "mythconfig.h"
00016 #include "nuppeldecoder.h"
00017 #include "NuppelVideoPlayer.h"
00018 #include "remoteencoder.h"
00019 #include "mythcontext.h"
00020 #include "mythdbcon.h"
00021
00022 #include "minilzo.h"
00023
00024 #ifdef WORDS_BIGENDIAN
00025 extern "C" {
00026 #include "libavutil/bswap.h"
00027 }
00028 #endif
00029
00030 #define LOC QString("NVD: ")
00031 #define LOC_ERR QString("NVD Error: ")
00032
00033 NuppelDecoder::NuppelDecoder(NuppelVideoPlayer *parent, ProgramInfo *pginfo)
00034 : DecoderBase(parent, pginfo),
00035 rtjd(0), video_width(0), video_height(0), video_size(0),
00036 video_frame_rate(0.0f), audio_samplerate(44100),
00037 #ifdef WORDS_BIGENDIAN
00038 audio_bits_per_sample(0),
00039 #endif
00040 ffmpeg_extradatasize(0), ffmpeg_extradata(0), usingextradata(false),
00041 disablevideo(false), totalLength(0), totalFrames(0), effdsp(0),
00042 directframe(NULL), decoded_video_frame(NULL),
00043 mpa_vidcodec(0), mpa_vidctx(0), mpa_audcodec(0), mpa_audctx(0),
00044 audioSamples(new short int[AVCODEC_MAX_AUDIO_FRAME_SIZE]),
00045 directrendering(false),
00046 lastct('1'), strm(0), buf(0), buf2(0),
00047 videosizetotal(0), videoframesread(0), setreadahead(false)
00048 {
00049
00050 memset(&fileheader, 0, sizeof(rtfileheader));
00051 memset(&frameheader, 0, sizeof(rtframeheader));
00052 memset(&extradata, 0, sizeof(extendeddata));
00053 memset(&tmppicture, 0, sizeof(AVPicture));
00054 planes[0] = planes[1] = planes[2] = 0;
00055 bzero(audioSamples, AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof(short int));
00056
00057
00058 positionMapType = MARK_KEYFRAME;
00059 lastKey = 0;
00060 framesPlayed = 0;
00061 getrawframes = false;
00062 getrawvideo = false;
00063
00064 rtjd = new RTjpeg();
00065 int format = RTJ_YUV420;
00066 rtjd->SetFormat(&format);
00067
00068 avcodeclock.lock();
00069 avcodec_init();
00070 avcodec_register_all();
00071 avcodeclock.unlock();
00072
00073 if (lzo_init() != LZO_E_OK)
00074 {
00075 VERBOSE(VB_IMPORTANT, "NuppelDecoder: lzo_init() failed, aborting");
00076 errored = true;
00077 return;
00078 }
00079 }
00080
00081 NuppelDecoder::~NuppelDecoder()
00082 {
00083 if (rtjd)
00084 delete rtjd;
00085 if (ffmpeg_extradata)
00086 delete [] ffmpeg_extradata;
00087 if (buf)
00088 delete [] buf;
00089 if (buf2)
00090 delete [] buf2;
00091 if (strm)
00092 delete [] strm;
00093 if (audioSamples)
00094 delete [] audioSamples;
00095 while(! StoredData.isEmpty()) {
00096 delete StoredData.first();
00097 StoredData.removeFirst();
00098 }
00099 CloseAVCodecVideo();
00100 CloseAVCodecAudio();
00101 }
00102
00103 bool NuppelDecoder::CanHandle(char testbuf[kDecoderProbeBufferSize],
00104 int)
00105 {
00106 if (!strncmp(testbuf, "NuppelVideo", 11) ||
00107 !strncmp(testbuf, "MythTVVideo", 11))
00108 return true;
00109 return false;
00110 }
00111
00112 MythCodecID NuppelDecoder::GetVideoCodecID(void) const
00113 {
00114 MythCodecID value = kCodec_NONE;
00115 if (mpa_vidcodec)
00116 {
00117 if (QString(mpa_vidcodec->name) == "mpeg4")
00118 value = kCodec_NUV_MPEG4;
00119 }
00120 else if (usingextradata && extradata.video_fourcc == FOURCC_DIVX)
00121 value = kCodec_NUV_MPEG4;
00122 else
00123 value = kCodec_NUV_RTjpeg;
00124 return (value);
00125 }
00126
00127 bool NuppelDecoder::ReadFileheader(struct rtfileheader *fh)
00128 {
00129 if (ringBuffer->Read(fh, FILEHEADERSIZE) != FILEHEADERSIZE)
00130 return false;
00131
00132 #ifdef WORDS_BIGENDIAN
00133 fh->width = bswap_32(fh->width);
00134 fh->height = bswap_32(fh->height);
00135 fh->desiredwidth = bswap_32(fh->desiredwidth);
00136 fh->desiredheight = bswap_32(fh->desiredheight);
00137 fh->aspect = bswap_dbl(fh->aspect);
00138 fh->fps = bswap_dbl(fh->fps);
00139 fh->videoblocks = bswap_32(fh->videoblocks);
00140 fh->audioblocks = bswap_32(fh->audioblocks);
00141 fh->textsblocks = bswap_32(fh->textsblocks);
00142 fh->keyframedist = bswap_32(fh->keyframedist);
00143 #endif
00144
00145 return true;
00146 }
00147
00148 bool NuppelDecoder::ReadFrameheader(struct rtframeheader *fh)
00149 {
00150 if (ringBuffer->Read(fh, FRAMEHEADERSIZE) != FRAMEHEADERSIZE)
00151 return false;
00152
00153 #ifdef WORDS_BIGENDIAN
00154 fh->timecode = bswap_32(fh->timecode);
00155 fh->packetlength = bswap_32(fh->packetlength);
00156 #endif
00157
00158 return true;
00159 }
00160
00161 int NuppelDecoder::OpenFile(RingBuffer *rbuffer, bool novideo,
00162 char testbuf[kDecoderProbeBufferSize],
00163 int)
00164 {
00165 (void)testbuf;
00166
00167 ringBuffer = rbuffer;
00168 disablevideo = novideo;
00169
00170 struct rtframeheader frameheader;
00171 long long startpos = 0;
00172 int foundit = 0;
00173 char ftype;
00174 char *space;
00175
00176 if (!ReadFileheader(&fileheader))
00177 {
00178 VERBOSE(VB_IMPORTANT, QString( "Error reading file: %1").arg( ringBuffer->GetFilename()));
00179 return -1;
00180 }
00181
00182 while ((QString(fileheader.finfo) != "NuppelVideo") &&
00183 (QString(fileheader.finfo) != "MythTVVideo"))
00184 {
00185 ringBuffer->Seek(startpos, SEEK_SET);
00186 char dummychar;
00187 ringBuffer->Read(&dummychar, 1);
00188
00189 startpos = ringBuffer->GetReadPosition();
00190
00191 if (!ReadFileheader(&fileheader))
00192 {
00193 VERBOSE(VB_IMPORTANT, QString( "Error reading file: %1").arg( ringBuffer->GetFilename()));
00194 return -1;
00195 }
00196
00197 if (startpos > 20000)
00198 {
00199 VERBOSE(VB_IMPORTANT, QString( "Bad file: %1").arg(ringBuffer->GetFilename().ascii()));
00200 return -1;
00201 }
00202 }
00203
00204 if (fileheader.aspect > .999 && fileheader.aspect < 1.001)
00205 fileheader.aspect = 4.0 / 3;
00206 current_aspect = fileheader.aspect;
00207
00208 GetNVP()->SetVideoParams(fileheader.width, fileheader.height,
00209 fileheader.fps, fileheader.keyframedist,
00210 fileheader.aspect);
00211
00212 video_width = fileheader.width;
00213 video_height = fileheader.height;
00214 video_size = video_height * video_width * 3 / 2;
00215 keyframedist = fileheader.keyframedist;
00216 video_frame_rate = fileheader.fps;
00217
00218 if (!ReadFrameheader(&frameheader))
00219 {
00220 VERBOSE(VB_IMPORTANT, "File not big enough for a header");
00221 return -1;
00222 }
00223 if (frameheader.frametype != 'D')
00224 {
00225 VERBOSE(VB_IMPORTANT,"Illegal file format");
00226 return -1;
00227 }
00228
00229 space = new char[video_size];
00230
00231 if (frameheader.comptype == 'F')
00232 {
00233 ffmpeg_extradatasize = frameheader.packetlength;
00234 if (ffmpeg_extradatasize > 0)
00235 {
00236 ffmpeg_extradata = new uint8_t[ffmpeg_extradatasize];
00237 if (frameheader.packetlength != ringBuffer->Read(ffmpeg_extradata,
00238 frameheader.packetlength))
00239 {
00240 VERBOSE(VB_IMPORTANT,"File not big enough for first frame data");
00241 delete [] ffmpeg_extradata;
00242 ffmpeg_extradata = NULL;
00243 delete [] space;
00244 return -1;
00245 }
00246 }
00247 }
00248 else
00249 {
00250 if (frameheader.packetlength != ringBuffer->Read(space,
00251 frameheader.packetlength))
00252 {
00253 VERBOSE(VB_IMPORTANT,"File not big enough for first frame data");
00254 delete [] space;
00255 return -1;
00256 }
00257 }
00258
00259 if ((video_height & 1) == 1)
00260 {
00261 video_height--;
00262 VERBOSE(VB_IMPORTANT,QString("Incompatible video height, reducing to %1")
00263 .arg( video_height));
00264 }
00265
00266 startpos = ringBuffer->GetReadPosition();
00267
00268 ReadFrameheader(&frameheader);
00269
00270 if (frameheader.frametype == 'X')
00271 {
00272 if (frameheader.packetlength != EXTENDEDSIZE)
00273 {
00274 VERBOSE(VB_IMPORTANT,"Corrupt file. Bad extended frame.");
00275 }
00276 else
00277 {
00278 ringBuffer->Read(&extradata, frameheader.packetlength);
00279 #ifdef WORDS_BIGENDIAN
00280 struct extendeddata *ed = &extradata;
00281 ed->version = bswap_32(ed->version);
00282 ed->video_fourcc = bswap_32(ed->video_fourcc);
00283 ed->audio_fourcc = bswap_32(ed->audio_fourcc);
00284 ed->audio_sample_rate = bswap_32(ed->audio_sample_rate);
00285 ed->audio_bits_per_sample = bswap_32(ed->audio_bits_per_sample);
00286 ed->audio_channels = bswap_32(ed->audio_channels);
00287 ed->audio_compression_ratio = bswap_32(ed->audio_compression_ratio);
00288 ed->audio_quality = bswap_32(ed->audio_quality);
00289 ed->rtjpeg_quality = bswap_32(ed->rtjpeg_quality);
00290 ed->rtjpeg_luma_filter = bswap_32(ed->rtjpeg_luma_filter);
00291 ed->rtjpeg_chroma_filter = bswap_32(ed->rtjpeg_chroma_filter);
00292 ed->lavc_bitrate = bswap_32(ed->lavc_bitrate);
00293 ed->lavc_qmin = bswap_32(ed->lavc_qmin);
00294 ed->lavc_qmax = bswap_32(ed->lavc_qmax);
00295 ed->lavc_maxqdiff = bswap_32(ed->lavc_maxqdiff);
00296 ed->seektable_offset = bswap_64(ed->seektable_offset);
00297 ed->keyframeadjust_offset = bswap_64(ed->keyframeadjust_offset);
00298 #endif
00299 usingextradata = true;
00300 ReadFrameheader(&frameheader);
00301 }
00302 }
00303
00304 if (usingextradata && extradata.seektable_offset > 0)
00305 {
00306 long long currentpos = ringBuffer->GetReadPosition();
00307 struct rtframeheader seek_frameheader;
00308
00309 int seekret = ringBuffer->Seek(extradata.seektable_offset, SEEK_SET);
00310 if (seekret == -1)
00311 {
00312 VERBOSE(VB_IMPORTANT,
00313 QString("NuppelDecoder::OpenFile(): seek error (%1)")
00314 .arg(strerror(errno)));
00315 }
00316
00317 ReadFrameheader(&seek_frameheader);
00318
00319 if (seek_frameheader.frametype != 'Q')
00320 {
00321 VERBOSE(VB_IMPORTANT, QString( "Invalid seektable (frametype %1)")
00322 .arg((int)seek_frameheader.frametype));
00323 }
00324 else
00325 {
00326 if (seek_frameheader.packetlength > 0)
00327 {
00328 char *seekbuf = new char[seek_frameheader.packetlength];
00329 ringBuffer->Read(seekbuf, seek_frameheader.packetlength);
00330
00331 int numentries = seek_frameheader.packetlength /
00332 sizeof(struct seektable_entry);
00333 struct seektable_entry ste;
00334 int offset = 0;
00335
00336 m_positionMap.clear();
00337 m_positionMap.reserve(numentries);
00338
00339 for (int z = 0; z < numentries; z++)
00340 {
00341 memcpy(&ste, seekbuf + offset,
00342 sizeof(struct seektable_entry));
00343 #ifdef WORDS_BIGENDIAN
00344 ste.file_offset = bswap_64(ste.file_offset);
00345 ste.keyframe_number = bswap_32(ste.keyframe_number);
00346 #endif
00347 offset += sizeof(struct seektable_entry);
00348
00349 PosMapEntry e = {ste.keyframe_number,
00350 ste.keyframe_number * keyframedist,
00351 ste.file_offset};
00352 m_positionMap.push_back(e);
00353 }
00354 hasFullPositionMap = true;
00355 totalLength = (int)((ste.keyframe_number * keyframedist * 1.0) /
00356 video_frame_rate);
00357 totalFrames = (long long)ste.keyframe_number * keyframedist;
00358 GetNVP()->SetFileLength(totalLength, totalFrames);
00359
00360 delete [] seekbuf;
00361 }
00362 else
00363 VERBOSE(VB_IMPORTANT, "0 length seek table");
00364 }
00365
00366 ringBuffer->Seek(currentpos, SEEK_SET);
00367 }
00368
00369 if (usingextradata && extradata.keyframeadjust_offset > 0 &&
00370 hasFullPositionMap)
00371 {
00372 long long currentpos = ringBuffer->GetReadPosition();
00373 struct rtframeheader kfa_frameheader;
00374
00375 int kfa_ret = ringBuffer->Seek(extradata.keyframeadjust_offset,
00376 SEEK_SET);
00377 if (kfa_ret == -1)
00378 {
00379 VERBOSE(VB_IMPORTANT,
00380 QString("NuppelDecoder::OpenFile(): keyframeadjust (%1)")
00381 .arg(strerror(errno)));
00382 }
00383
00384 ringBuffer->Read(&kfa_frameheader, FRAMEHEADERSIZE);
00385
00386 if (kfa_frameheader.frametype != 'K')
00387 {
00388 VERBOSE(VB_IMPORTANT, QString( "Invalid key frame adjust table (frametype %1)")
00389 .arg((int)kfa_frameheader.frametype));
00390 }
00391 else
00392 {
00393 if (kfa_frameheader.packetlength > 0)
00394 {
00395 char *kfa_buf = new char[kfa_frameheader.packetlength];
00396 ringBuffer->Read(kfa_buf, kfa_frameheader.packetlength);
00397
00398 int numentries = kfa_frameheader.packetlength /
00399 sizeof(struct kfatable_entry);
00400 struct kfatable_entry kfate;
00401 int offset = 0;
00402 int adjust = 0;
00403 QMap<long long, int> keyFrameAdjustMap;
00404
00405 for (int z = 0; z < numentries; z++)
00406 {
00407 memcpy(&kfate, kfa_buf + offset,
00408 sizeof(struct kfatable_entry));
00409 #ifdef WORDS_BIGENDIAN
00410 kfate.adjust = bswap_32(kfate.adjust);
00411 kfate.keyframe_number = bswap_32(kfate.keyframe_number);
00412 #endif
00413 offset += sizeof(struct kfatable_entry);
00414
00415 keyFrameAdjustMap[kfate.keyframe_number] = kfate.adjust;
00416 adjust += kfate.adjust;
00417 }
00418 hasKeyFrameAdjustTable = true;
00419
00420 totalLength -= (int)(adjust / video_frame_rate);
00421 totalFrames -= adjust;
00422 GetNVP()->SetFileLength(totalLength, totalFrames);
00423
00424 adjust = 0;
00425 for (unsigned int i=0; i < m_positionMap.size(); i++)
00426 {
00427 if (keyFrameAdjustMap.contains(m_positionMap[i].adjFrame))
00428 adjust += keyFrameAdjustMap[m_positionMap[i].adjFrame];
00429
00430 m_positionMap[i].adjFrame -= adjust;
00431 }
00432
00433 delete [] kfa_buf;
00434 }
00435 else
00436 VERBOSE(VB_IMPORTANT,"0 length key frame adjust table");
00437 }
00438
00439 ringBuffer->Seek(currentpos, SEEK_SET);
00440 }
00441
00442 while (frameheader.frametype != 'A' && frameheader.frametype != 'V' &&
00443 frameheader.frametype != 'S' && frameheader.frametype != 'T' &&
00444 frameheader.frametype != 'R')
00445 {
00446 ringBuffer->Seek(startpos, SEEK_SET);
00447
00448 char dummychar;
00449 ringBuffer->Read(&dummychar, 1);
00450
00451 startpos = ringBuffer->GetReadPosition();
00452
00453 if (!ReadFrameheader(&frameheader))
00454 {
00455 delete [] space;
00456 return -1;
00457 }
00458
00459 if (startpos > 20000)
00460 {
00461 delete [] space;
00462 return -1;
00463 }
00464 }
00465
00466 foundit = 0;
00467
00468 effdsp = audio_samplerate * 100;
00469 GetNVP()->SetEffDsp(effdsp);
00470
00471 if (usingextradata)
00472 {
00473 effdsp = extradata.audio_sample_rate * 100;
00474 GetNVP()->SetEffDsp(effdsp);
00475 audio_samplerate = extradata.audio_sample_rate;
00476 #ifdef WORDS_BIGENDIAN
00477
00478 audio_bits_per_sample = extradata.audio_bits_per_sample;
00479 #endif
00480 GetNVP()->SetAudioParams(extradata.audio_bits_per_sample,
00481 extradata.audio_channels,
00482 extradata.audio_sample_rate,
00483 false );
00484 GetNVP()->ReinitAudio();
00485 foundit = 1;
00486 }
00487
00488 while (!foundit)
00489 {
00490 ftype = ' ';
00491 if (frameheader.frametype == 'S')
00492 {
00493 if (frameheader.comptype == 'A')
00494 {
00495 effdsp = frameheader.timecode;
00496 if (effdsp > 0)
00497 {
00498 GetNVP()->SetEffDsp(effdsp);
00499 foundit = 1;
00500 continue;
00501 }
00502 }
00503 }
00504 if (frameheader.frametype != 'R' && frameheader.packetlength != 0)
00505 {
00506 if (frameheader.packetlength != ringBuffer->Read(space,
00507 frameheader.packetlength))
00508 {
00509 foundit = 1;
00510 continue;
00511 }
00512 }
00513
00514 long long startpos2 = ringBuffer->GetReadPosition();
00515
00516 foundit = !ReadFrameheader(&frameheader);
00517
00518 bool framesearch = false;
00519
00520 while (frameheader.frametype != 'A' && frameheader.frametype != 'V' &&
00521 frameheader.frametype != 'S' && frameheader.frametype != 'T' &&
00522 frameheader.frametype != 'R' && frameheader.frametype != 'X')
00523 {
00524 if (!framesearch)
00525 VERBOSE(VB_IMPORTANT, "Searching for frame header.");
00526
00527 framesearch = true;
00528
00529 ringBuffer->Seek(startpos2, SEEK_SET);
00530
00531 char dummychar;
00532 ringBuffer->Read(&dummychar, 1);
00533
00534 startpos2 = ringBuffer->GetReadPosition();
00535
00536 foundit = !ReadFrameheader(&frameheader);
00537 if (foundit)
00538 break;
00539 }
00540 }
00541
00542 delete [] space;
00543
00544 setreadahead = false;
00545
00546
00547 if (usingextradata && extradata.video_fourcc == FOURCC_DIVX)
00548 setreadahead = true;
00549
00550 bitrate = 0;
00551 ringBuffer->UpdateRawBitrate(GetRawBitrate());
00552
00553 videosizetotal = 0;
00554 videoframesread = 0;
00555
00556 ringBuffer->Seek(startpos, SEEK_SET);
00557
00558 buf = new unsigned char[video_size];
00559 strm = new unsigned char[video_size * 2];
00560
00561 if (hasFullPositionMap)
00562 return 1;
00563
00564 if (SyncPositionMap())
00565 return 1;
00566
00567 return 0;
00568 }
00569
00570 int get_nuppel_buffer(struct AVCodecContext *c, AVFrame *pic)
00571 {
00572 NuppelDecoder *nd = (NuppelDecoder *)(c->opaque);
00573
00574 int i;
00575
00576 for (i = 0; i < 3; i++)
00577 {
00578 pic->data[i] = nd->directframe->buf + nd->directframe->offsets[i];
00579 pic->linesize[i] = nd->directframe->pitches[i];
00580 }
00581
00582 pic->opaque = nd->directframe;
00583 pic->type = FF_BUFFER_TYPE_USER;
00584
00585 pic->age = 256 * 256 * 256 * 64;
00586
00587 return 1;
00588 }
00589
00590 void release_nuppel_buffer(struct AVCodecContext *c, AVFrame *pic)
00591 {
00592 (void)c;
00593 assert(pic->type == FF_BUFFER_TYPE_USER);
00594
00595 NuppelDecoder *nd = (NuppelDecoder *)(c->opaque);
00596 if (nd && nd->GetNVP() && nd->GetNVP()->getVideoOutput())
00597 nd->GetNVP()->getVideoOutput()->DeLimboFrame((VideoFrame*)pic->opaque);
00598
00599 int i;
00600 for (i = 0; i < 4; i++)
00601 pic->data[i] = NULL;
00602 }
00603
00604 bool NuppelDecoder::InitAVCodecVideo(int codec)
00605 {
00606 if (mpa_vidcodec)
00607 CloseAVCodecVideo();
00608
00609 if (usingextradata)
00610 {
00611 switch(extradata.video_fourcc)
00612 {
00613 case FOURCC_DIVX: codec = CODEC_ID_MPEG4; break;
00614 case FOURCC_WMV1: codec = CODEC_ID_WMV1; break;
00615 case FOURCC_DIV3: codec = CODEC_ID_MSMPEG4V3; break;
00616 case FOURCC_MP42: codec = CODEC_ID_MSMPEG4V2; break;
00617 case FOURCC_MPG4: codec = CODEC_ID_MSMPEG4V1; break;
00618 case FOURCC_MJPG: codec = CODEC_ID_MJPEG; break;
00619 case FOURCC_H263: codec = CODEC_ID_H263; break;
00620 case FOURCC_H264: codec = CODEC_ID_H264; break;
00621 case FOURCC_I263: codec = CODEC_ID_H263I; break;
00622 case FOURCC_MPEG: codec = CODEC_ID_MPEG1VIDEO; break;
00623 case FOURCC_MPG2: codec = CODEC_ID_MPEG2VIDEO; break;
00624 case FOURCC_HFYU: codec = CODEC_ID_HUFFYUV; break;
00625 default: codec = -1;
00626 }
00627 }
00628 mpa_vidcodec = avcodec_find_decoder((enum CodecID)codec);
00629
00630 if (!mpa_vidcodec)
00631 {
00632 if (usingextradata)
00633 VERBOSE(VB_IMPORTANT, QString("couldn't find video codec (%1)").arg(extradata.video_fourcc));
00634 else
00635 VERBOSE(VB_IMPORTANT, "couldn't find video codec");
00636 return false;
00637 }
00638
00639 if (mpa_vidcodec->capabilities & CODEC_CAP_DR1 && codec != CODEC_ID_MJPEG)
00640 directrendering = true;
00641
00642 if (mpa_vidctx)
00643 av_free(mpa_vidctx);
00644
00645 mpa_vidctx = avcodec_alloc_context();
00646
00647 mpa_vidctx->codec_id = (enum CodecID)codec;
00648 mpa_vidctx->width = video_width;
00649 mpa_vidctx->height = video_height;
00650 mpa_vidctx->error_resilience = 2;
00651 mpa_vidctx->bits_per_sample = 12;
00652
00653 if (directrendering)
00654 {
00655 mpa_vidctx->flags |= CODEC_FLAG_EMU_EDGE;
00656 mpa_vidctx->draw_horiz_band = NULL;
00657 mpa_vidctx->get_buffer = get_nuppel_buffer;
00658 mpa_vidctx->release_buffer = release_nuppel_buffer;
00659 mpa_vidctx->opaque = (void *)this;
00660 }
00661 if (ffmpeg_extradatasize > 0)
00662 {
00663 mpa_vidctx->flags |= CODEC_FLAG_EXTERN_HUFF;
00664 mpa_vidctx->extradata = ffmpeg_extradata;
00665 mpa_vidctx->extradata_size = ffmpeg_extradatasize;
00666 }
00667
00668 QMutexLocker locker(&avcodeclock);
00669 if (avcodec_open(mpa_vidctx, mpa_vidcodec) < 0)
00670 {
00671 VERBOSE(VB_IMPORTANT, LOC + "Couldn't find lavc video codec");
00672 return false;
00673 }
00674
00675 return true;
00676 }
00677
00678 void NuppelDecoder::CloseAVCodecVideo(void)
00679 {
00680 QMutexLocker locker(&avcodeclock);
00681
00682 if (mpa_vidcodec)
00683 {
00684 avcodec_close(mpa_vidctx);
00685
00686 if (mpa_vidctx)
00687 {
00688 av_free(mpa_vidctx);
00689 mpa_vidctx = NULL;
00690 }
00691 }
00692 }
00693
00694 bool NuppelDecoder::InitAVCodecAudio(int codec)
00695 {
00696 if (mpa_audcodec)
00697 CloseAVCodecAudio();
00698
00699 if (usingextradata)
00700 {
00701 switch(extradata.audio_fourcc)
00702 {
00703 case FOURCC_LAME: codec = CODEC_ID_MP3; break;
00704 case FOURCC_AC3 : codec = CODEC_ID_AC3; break;
00705 default: codec = -1;
00706 }
00707 }
00708 mpa_audcodec = avcodec_find_decoder((enum CodecID)codec);
00709
00710 if (!mpa_audcodec)
00711 {
00712 if (usingextradata)
00713 VERBOSE(VB_IMPORTANT, QString("couldn't find audio codec (%1)")
00714 .arg(extradata.audio_fourcc));
00715 else
00716 VERBOSE(VB_IMPORTANT, "couldn't find audio codec");
00717 return false;
00718 }
00719
00720 if (mpa_audctx)
00721 av_free(mpa_audctx);
00722
00723 mpa_audctx = avcodec_alloc_context();
00724
00725 mpa_audctx->codec_id = (enum CodecID)codec;
00726
00727 QMutexLocker locker(&avcodeclock);
00728 if (avcodec_open(mpa_audctx, mpa_audcodec) < 0)
00729 {
00730 VERBOSE(VB_IMPORTANT, LOC + "Couldn't find lavc audio codec");
00731 return false;
00732 }
00733
00734 return true;
00735 }
00736
00737 void NuppelDecoder::CloseAVCodecAudio(void)
00738 {
00739 QMutexLocker locker(&avcodeclock);
00740
00741 if (mpa_audcodec)
00742 {
00743 avcodec_close(mpa_audctx);
00744
00745 if (mpa_audctx)
00746 {
00747 av_free(mpa_audctx);
00748 mpa_audctx = NULL;
00749 }
00750 }
00751 }
00752
00753 static void CopyToVideo(unsigned char *buf, int video_width,
00754 int video_height, VideoFrame *frame)
00755 {
00756 uint ysize = video_width * video_height;
00757 uint uvsize = ysize >> 2;
00758
00759 unsigned char *planes[3];
00760 planes[0] = buf;
00761 planes[1] = planes[0] + ysize;
00762 planes[2] = planes[1] + uvsize;
00763
00764 memcpy(frame->buf + frame->offsets[0], planes[0], ysize);
00765 memcpy(frame->buf + frame->offsets[1], planes[1], uvsize);
00766 memcpy(frame->buf + frame->offsets[2], planes[2], uvsize);
00767 }
00768
00769 bool NuppelDecoder::DecodeFrame(struct rtframeheader *frameheader,
00770 unsigned char *lstrm, VideoFrame *frame)
00771 {
00772 int r;
00773 lzo_uint out_len;
00774 int compoff = 0;
00775
00776 unsigned char *outbuf = frame->buf;
00777 directframe = frame;
00778
00779 if (!buf2)
00780 {
00781 buf2 = new unsigned char[video_size + 64];
00782 planes[0] = buf;
00783 planes[1] = planes[0] + video_width * video_height;
00784 planes[2] = planes[1] + (video_width * video_height) / 4;
00785 }
00786
00787 if (frameheader->comptype == 'N') {
00788 memset(outbuf, 0, video_width * video_height);
00789 memset(outbuf + video_width * video_height, 127,
00790 (video_width * video_height)/2);
00791 return true;
00792 }
00793
00794 if (frameheader->comptype == 'L') {
00795 switch(lastct) {
00796 case '0': case '3':
00797 CopyToVideo(buf2, video_width, video_height, frame);
00798 break;
00799 case '1': case '2':
00800 default:
00801 CopyToVideo(buf, video_width, video_height, frame);
00802 break;
00803 }
00804 return true;
00805 }
00806
00807 compoff = 1;
00808 if (frameheader->comptype == '2' || frameheader->comptype == '3')
00809 compoff=0;
00810
00811 lastct = frameheader->comptype;
00812
00813 if (!compoff)
00814 {
00815 r = lzo1x_decompress(lstrm, frameheader->packetlength, buf2, &out_len,
00816 NULL);
00817 if (r != LZO_E_OK)
00818 {
00819 VERBOSE(VB_IMPORTANT, "minilzo: can't decompress illegal data");
00820 }
00821 }
00822
00823 if (frameheader->comptype == '0')
00824 {
00825 CopyToVideo(lstrm, video_width, video_height, frame);
00826 return true;
00827 }
00828
00829 if (frameheader->comptype == '3')
00830 {
00831 CopyToVideo(buf2, video_width, video_height, frame);
00832 return true;
00833 }
00834
00835 if (frameheader->comptype == '2' || frameheader->comptype == '1')
00836 {
00837 if (compoff)
00838 rtjd->Decompress((int8_t*)lstrm, planes);
00839 else
00840 rtjd->Decompress((int8_t*)buf2, planes);
00841
00842 CopyToVideo(buf, video_width, video_height, frame);
00843 }
00844 else
00845 {
00846 if (!mpa_vidcodec)
00847 InitAVCodecVideo(frameheader->comptype - '3');
00848
00849 AVFrame mpa_pic;
00850
00851 {
00852 QMutexLocker locker(&avcodeclock);
00853
00854 int gotpicture = 0;
00855 int ret = avcodec_decode_video(mpa_vidctx, &mpa_pic, &gotpicture,
00856 lstrm, frameheader->packetlength);
00857 directframe = NULL;
00858 if (ret < 0)
00859 {
00860 VERBOSE(VB_PLAYBACK, LOC_ERR +
00861 "avcodec_decode_video returned: "<<ret);
00862 return false;
00863 }
00864 else if (!gotpicture)
00865 {
00866 return false;
00867 }
00868 }
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 if (directrendering)
00891 return true;
00892
00893 avpicture_fill(&tmppicture, outbuf, PIX_FMT_YUV420P, video_width,
00894 video_height);
00895
00896 img_convert(&tmppicture, PIX_FMT_YUV420P, (AVPicture *)&mpa_pic,
00897 mpa_vidctx->pix_fmt, video_width, video_height);
00898 }
00899
00900 return true;
00901 }
00902
00903 bool NuppelDecoder::isValidFrametype(char type)
00904 {
00905 switch (type)
00906 {
00907 case 'A': case 'V': case 'S': case 'T': case 'R': case 'X':
00908 case 'M': case 'D': case 'Q': case 'K':
00909 return true;
00910 default:
00911 return false;
00912 }
00913
00914 return false;
00915 }
00916
00917 void NuppelDecoder::StoreRawData(unsigned char *newstrm)
00918 {
00919 unsigned char *strmcpy;
00920 if (newstrm)
00921 {
00922 strmcpy = new unsigned char[frameheader.packetlength];
00923 memcpy(strmcpy, newstrm, frameheader.packetlength);
00924 }
00925 else
00926 strmcpy = NULL;
00927
00928 StoredData.append(new RawDataList(frameheader, strmcpy));
00929 }
00930
00931
00932 long NuppelDecoder::UpdateStoredFrameNum(long framenum)
00933 {
00934 long sync_offset = 0;
00935 for (RawDataList *data = StoredData.first(); data; data = StoredData.next())
00936 {
00937 if (data->frameheader.frametype == 'S' &&
00938 data->frameheader.comptype == 'V')
00939 {
00940 data->frameheader.timecode = framenum;
00941 return sync_offset;
00942 }
00943 sync_offset += FRAMEHEADERSIZE;
00944 if (data->packet)
00945 sync_offset += data->frameheader.packetlength;
00946 }
00947 return 0;
00948 }
00949
00950 void NuppelDecoder::WriteStoredData(RingBuffer *rb, bool storevid,
00951 long timecodeOffset)
00952 {
00953 RawDataList *data;
00954 while(! StoredData.isEmpty()) {
00955 data = StoredData.first();
00956
00957 if (data->frameheader.frametype != 'S')
00958 data->frameheader.timecode -= timecodeOffset;
00959
00960 if (storevid || data->frameheader.frametype != 'V')
00961 {
00962 rb->Write(&(data->frameheader), FRAMEHEADERSIZE);
00963 if (data->packet)
00964 rb->Write(data->packet, data->frameheader.packetlength);
00965 }
00966 StoredData.removeFirst();
00967 delete data;
00968 }
00969 }
00970
00971 void NuppelDecoder::ClearStoredData()
00972 {
00973 RawDataList *data;
00974 while(!StoredData.isEmpty()) {
00975 data = StoredData.first();
00976 StoredData.removeFirst();
00977 delete data;
00978 }
00979 }
00980
00981
00982
00983
00984
00985 bool NuppelDecoder::GetFrame(int avignore)
00986 {
00987 bool gotvideo = false;
00988 bool ret = false;
00989 int seeklen = 0;
00990
00991 decoded_video_frame = NULL;
00992
00993 while (!gotvideo)
00994 {
00995 long long currentposition = ringBuffer->GetReadPosition();
00996 if (waitingForChange && currentposition + 4 >= readAdjust)
00997 {
00998 FileChanged();
00999 currentposition = ringBuffer->GetReadPosition();
01000 }
01001
01002 if (!ReadFrameheader(&frameheader))
01003 {
01004 ateof = true;
01005 GetNVP()->SetEof();
01006 return false;
01007 }
01008
01009
01010 if (!ringBuffer->LiveMode() &&
01011 ((frameheader.frametype == 'Q') || (frameheader.frametype == 'K')))
01012 {
01013 ateof = true;
01014 GetNVP()->SetEof();
01015 return false;
01016 }
01017
01018 bool framesearch = false;
01019
01020 while (!isValidFrametype(frameheader.frametype))
01021 {
01022 if (!framesearch)
01023 VERBOSE(VB_IMPORTANT, "Searching for frame header.");
01024
01025 framesearch = true;
01026
01027 ringBuffer->Seek((long long)seeklen-FRAMEHEADERSIZE, SEEK_CUR);
01028
01029 if (!ReadFrameheader(&frameheader))
01030 {
01031 ateof = true;
01032 GetNVP()->SetEof();
01033 return false;
01034 }
01035 seeklen = 1;
01036 }
01037
01038 if (frameheader.frametype == 'M')
01039 {
01040 int sizetoskip = sizeof(rtfileheader) - sizeof(rtframeheader);
01041 char *dummy = new char[sizetoskip + 1];
01042
01043 if (ringBuffer->Read(dummy, sizetoskip) != sizetoskip)
01044 {
01045 delete [] dummy;
01046 ateof = true;
01047 GetNVP()->SetEof();
01048 return false;
01049 }
01050
01051 delete [] dummy;
01052 continue;
01053 }
01054
01055 if (frameheader.frametype == 'R')
01056 {
01057 if (getrawframes)
01058 StoreRawData(NULL);
01059 continue;
01060 }
01061
01062 if (frameheader.frametype == 'S')
01063 {
01064 if (frameheader.comptype == 'A')
01065 {
01066 if (frameheader.timecode > 2000000 &&
01067 frameheader.timecode < 5500000)
01068 {
01069 effdsp = frameheader.timecode;
01070 GetNVP()->SetEffDsp(effdsp);
01071 }
01072 }
01073 else if (frameheader.comptype == 'V')
01074 {
01075 lastKey = frameheader.timecode;
01076 framesPlayed = frameheader.timecode - 1;
01077
01078 if (!hasFullPositionMap)
01079 {
01080 long long last_index = 0;
01081 long long this_index = lastKey / keyframedist;
01082 if (!m_positionMap.empty())
01083 last_index =
01084 m_positionMap[m_positionMap.size() - 1].index;
01085
01086 if (this_index > last_index)
01087 {
01088
01089 if (m_positionMap.capacity() == m_positionMap.size())
01090 m_positionMap.reserve(m_positionMap.size() + 60);
01091 PosMapEntry entry = {this_index, lastKey,
01092 currentposition};
01093 m_positionMap.push_back(entry);
01094 }
01095 }
01096 }
01097 if (getrawframes)
01098 StoreRawData(NULL);
01099 }
01100
01101 if (frameheader.packetlength > 0)
01102 {
01103 if (frameheader.packetlength > 10485760)
01104 {
01105 VERBOSE(VB_IMPORTANT, QString("Broken packet: %1 %2")
01106 .arg(frameheader.frametype)
01107 .arg(frameheader.packetlength));
01108 ateof = true;
01109 GetNVP()->SetEof();
01110 return false;
01111 }
01112 if (ringBuffer->Read(strm, frameheader.packetlength) !=
01113 frameheader.packetlength)
01114 {
01115 ateof = true;
01116 GetNVP()->SetEof();
01117 return false;
01118 }
01119 }
01120 else
01121 continue;
01122
01123 if (frameheader.frametype == 'V')
01124 {
01125 if (avignore == -1)
01126 {
01127 framesPlayed++;
01128 gotvideo = 1;
01129 continue;
01130 }
01131
01132 VideoFrame *buf = GetNVP()->GetNextVideoFrame();
01133
01134 ret = DecodeFrame(&frameheader, strm, buf);
01135 if (!ret)
01136 {
01137 GetNVP()->DiscardVideoFrame(buf);
01138 continue;
01139 }
01140
01141 buf->frameNumber = framesPlayed;
01142 GetNVP()->ReleaseNextVideoFrame(buf, frameheader.timecode);
01143
01144
01145
01146 if (directframe)
01147 GetNVP()->getVideoOutput()->DeLimboFrame(buf);
01148
01149 decoded_video_frame = buf;
01150 gotvideo = 1;
01151 if (getrawframes && getrawvideo)
01152 StoreRawData(strm);
01153 framesPlayed++;
01154
01155 if (!setreadahead)
01156 {
01157 videosizetotal += frameheader.packetlength;
01158 videoframesread++;
01159
01160 if (videoframesread > 15)
01161 {
01162 videosizetotal /= videoframesread;
01163
01164 float bps = (videosizetotal * 8.0f / 1024.0f *
01165 video_frame_rate);
01166 bitrate = (uint) (bps * 1.5f);
01167
01168 ringBuffer->UpdateRawBitrate(GetRawBitrate());
01169 setreadahead = true;
01170 }
01171 }
01172 continue;
01173 }
01174
01175 if (frameheader.frametype=='A' && avignore == 0)
01176 {
01177 if ((frameheader.comptype == '3') || (frameheader.comptype == 'A'))
01178 {
01179 if (getrawframes)
01180 StoreRawData(strm);
01181
01182 if (!mpa_audcodec)
01183 {
01184 if (frameheader.comptype == '3')
01185 InitAVCodecAudio(CODEC_ID_MP3);
01186 else if (frameheader.comptype == 'A')
01187 InitAVCodecAudio(CODEC_ID_AC3);
01188 else
01189 {
01190 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("GetFrame: "
01191 "Unknown audio comptype of '%1', skipping")
01192 .arg(frameheader.comptype));
01193 return false;
01194 }
01195 }
01196
01197 int packetlen = frameheader.packetlength;
01198 int ret = 0;
01199 int data_size = 0;
01200 unsigned char *ptr = strm;
01201
01202 QMutexLocker locker(&avcodeclock);
01203
01204 while (packetlen > 0)
01205 {
01206 data_size = 0;
01207
01208 ret = avcodec_decode_audio(mpa_audctx,
01209 audioSamples, &data_size, ptr, packetlen);
01210
01211 if (data_size)
01212 GetNVP()->AddAudioData((char *)audioSamples, data_size,
01213 frameheader.timecode);
01214
01215 packetlen -= ret;
01216 ptr += ret;
01217 }
01218 }
01219 else
01220 {
01221 getrawframes = 0;
01222 #ifdef WORDS_BIGENDIAN
01223
01224
01225 if (audio_bits_per_sample == 16) {
01226
01227 for (int i = 0; i < (frameheader.packetlength & ~1); i+=2) {
01228 char tmp;
01229 tmp = strm[i+1];
01230 strm[i+1] = strm[i];
01231 strm[i] = tmp;
01232 }
01233 }
01234 #endif
01235 VERBOSE(VB_PLAYBACK, QString("A audio timecode %1").arg(frameheader.timecode));
01236 GetNVP()->AddAudioData((char *)strm, frameheader.packetlength,
01237 frameheader.timecode);
01238 }
01239 }
01240
01241 if (frameheader.frametype == 'T' && avignore >= 0)
01242 {
01243 if (getrawframes)
01244 StoreRawData(strm);
01245
01246 GetNVP()->AddTextData(strm, frameheader.packetlength,
01247 frameheader.timecode, frameheader.comptype);
01248 }
01249
01250 if (frameheader.frametype == 'S' && frameheader.comptype == 'M')
01251 {
01252 unsigned char *eop = strm + frameheader.packetlength;
01253 unsigned char *cur = strm;
01254
01255 struct rtfileheader tmphead;
01256 struct rtfileheader *fh = &tmphead;
01257
01258 memcpy(fh, cur, frameheader.packetlength);
01259
01260 while (QString(fileheader.finfo) != "MythTVVideo" &&
01261 cur + frameheader.packetlength <= eop)
01262 {
01263 cur++;
01264 memcpy(fh, cur, frameheader.packetlength);
01265 }
01266
01267 if (QString(fileheader.finfo) == "MythTVVideo")
01268 {
01269 #ifdef WORDS_BIGENDIAN
01270 fh->width = bswap_32(fh->width);
01271 fh->height = bswap_32(fh->height);
01272 fh->desiredwidth = bswap_32(fh->desiredwidth);
01273 fh->desiredheight = bswap_32(fh->desiredheight);
01274 fh->aspect = bswap_dbl(fh->aspect);
01275 fh->fps = bswap_dbl(fh->fps);
01276 fh->videoblocks = bswap_32(fh->videoblocks);
01277 fh->audioblocks = bswap_32(fh->audioblocks);
01278 fh->textsblocks = bswap_32(fh->textsblocks);
01279 fh->keyframedist = bswap_32(fh->keyframedist);
01280 #endif
01281
01282 memcpy(&fileheader, fh, FRAMEHEADERSIZE);
01283
01284 if (fileheader.aspect > .999 && fileheader.aspect < 1.001)
01285 fileheader.aspect = 4.0 / 3;
01286 current_aspect = fileheader.aspect;
01287
01288 GetNVP()->SetVideoParams(fileheader.width, fileheader.height,
01289 fileheader.fps, fileheader.keyframedist,
01290 fileheader.aspect);
01291 }
01292 }
01293 }
01294
01295 framesRead = framesPlayed;
01296
01297 return true;
01298 }
01299
01300 void NuppelDecoder::SeekReset(long long newKey, uint skipFrames,
01301 bool doFlush, bool discardFrames)
01302 {
01303 VERBOSE(VB_PLAYBACK, LOC +
01304 QString("SeekReset(%1, %2, %3 flush, %4 discard)")
01305 .arg(newKey).arg(skipFrames)
01306 .arg((doFlush) ? "do" : "don't")
01307 .arg((discardFrames) ? "do" : "don't"));
01308
01309 DecoderBase::SeekReset(newKey, skipFrames, doFlush, discardFrames);
01310
01311 if (mpa_vidcodec && doFlush)
01312 avcodec_flush_buffers(mpa_vidctx);
01313
01314 if (discardFrames)
01315 GetNVP()->DiscardVideoFrames(doFlush);
01316
01317 for (;(skipFrames > 0) && !ateof; skipFrames--)
01318 {
01319 GetFrame(0);
01320 if (decoded_video_frame)
01321 GetNVP()->DiscardVideoFrame(decoded_video_frame);
01322 }
01323 }
01324
01325