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