MythTV  0.26-pre
nuppeldecoder.cpp
Go to the documentation of this file.
00001 // C headers
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 // C++ headers
00010 #include <algorithm>
00011 #include <iostream>
00012 using namespace std;
00013 
00014 // Qt headers
00015 #include <QMutex>
00016 
00017 // MythTV headers
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     // initialize structures
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     // set parent class variables
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         // Why only if using extradata?
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 /* AC3/DTS pass through */);
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     // mpeg4 encodes are small enough that this shouldn't matter
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         // Use video bitrate, ignore negligible audio bitrate
00601         bitrate = extradata.lavc_bitrate / 1000;
00602     }
00603     bitrate = max(bitrate, min_bitrate); // set minimum 1 Mb/s to be safe
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             // if directrendering, writes into buf
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 /* XXX: Broken
00935         if (mpa_pic->qscale_table != NULL && mpa_pic->qstride > 0)
00936         {
00937             int tablesize = mpa_pic->qstride * ((video_height + 15) / 16);
00938 
00939             if (frame->qstride != mpa_pic->qstride ||
00940                 frame->qscale_table == NULL)
00941             {
00942                 frame->qstride = mpa_pic->qstride;
00943 
00944                 if (frame->qscale_table)
00945                     delete [] frame->qscale_table;
00946 
00947                 frame->qscale_table = new unsigned char[tablesize];
00948             }
00949 
00950             memcpy(frame->qscale_table, mpa_pic->qscale_table, tablesize);
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 // The return value is the number of bytes in StoredData before the 'SV' frame
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; // the R-frame has no data packet
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) // arbitrary 10MB limit
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             // We need to make the frame available ourselves
01208             // if we are not using ffmpeg/avlib.
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                 // Why endian correct the audio buffer here?
01295                 // Don't big-endian clients have to do it in audiooutBlah.cpp?
01296                 if (audio_bits_per_sample == 16) {
01297                     // swap bytes
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 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends