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