MythTV  0.26-pre
NuppelVideoRecorder.cpp
Go to the documentation of this file.
00001 #include <cstdio>
00002 #include <cstdlib>
00003 #include <fcntl.h>
00004 #include <unistd.h>
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include "mythconfig.h"
00008 #if HAVE_SYS_SOUNDCARD_H
00009     #include <sys/soundcard.h>
00010 #elif HAVE_SOUNDCARD_H
00011     #include <soundcard.h>
00012 #endif
00013 #include <sys/ioctl.h>
00014 #include <sys/mman.h>
00015 #include <cerrno>
00016 #include <cmath>
00017 
00018 #include <QStringList>
00019 
00020 #include <iostream>
00021 using namespace std;
00022 
00023 #include "mythmiscutil.h"
00024 #include "mythcontext.h"
00025 #include "NuppelVideoRecorder.h"
00026 #include "channelbase.h"
00027 #include "filtermanager.h"
00028 #include "recordingprofile.h"
00029 #include "tv_rec.h"
00030 #include "tv_play.h"
00031 #include "audioinput.h"
00032 #include "mythlogging.h"
00033 #include "vbitext/cc.h"
00034 #include "vbitext/vbi.h"
00035 
00036 #if HAVE_BIGENDIAN
00037 extern "C" {
00038 #include "byteswap.h"
00039 }
00040 #endif
00041 
00042 extern "C" {
00043 #include "libswscale/swscale.h"
00044 }
00045 
00046 #ifdef USING_V4L2
00047 #include <linux/videodev2.h>
00048 
00049 #include "go7007_myth.h"
00050 
00051 #ifdef USING_V4L1
00052 #include <linux/videodev.h>
00053 #endif // USING_V4L1
00054 
00055 #ifndef MJPIOC_S_PARAMS
00056 #include "videodev_mjpeg.h"
00057 #endif
00058 
00059 #endif // USING_V4L2
00060 
00061 #define KEYFRAMEDIST   30
00062 
00063 #include "ringbuffer.h"
00064 #include "RTjpegN.h"
00065 
00066 #include "programinfo.h"
00067 
00068 #define LOC QString("NVR(%1): ").arg(videodevice)
00069 
00070 void NVRWriteThread::run(void)
00071 {
00072     RunProlog();
00073     m_parent->doWriteThread();
00074     RunEpilog();
00075 }
00076 
00077 void NVRAudioThread::run(void)
00078 {
00079     RunProlog();
00080     m_parent->doAudioThread();
00081     RunEpilog();
00082 }
00083 
00084 NuppelVideoRecorder::NuppelVideoRecorder(TVRec *rec, ChannelBase *channel) :
00085     V4LRecorder(rec), audio_device(NULL),
00086     write_thread(NULL), audio_thread(NULL)
00087 {
00088     channelObj = channel;
00089 
00090     fd = -1;
00091     channelfd = -1;
00092     lf = tf = 0;
00093     M1 = 0, M2 = 0, Q = 255;
00094     pid = pid2 = 0;
00095     inputchannel = 1;
00096     compression = 1;
00097     compressaudio = 1;
00098     usebttv = 1;
00099     width  = 352;
00100     height = 240;
00101     pip_mode = 0;
00102     video_aspect = 1.33333;
00103 
00104     skip_btaudio = false;
00105 
00106     framerate_multiplier = 1.0;
00107     height_multiplier = 1.0;
00108 
00109     mp3quality = 3;
00110     gf = NULL;
00111     rtjc = NULL;
00112     strm = NULL;
00113     mp3buf = NULL;
00114 
00115     transcoding = false;
00116 
00117     act_video_encode = 0;
00118     act_video_buffer = 0;
00119     video_buffer_count = 0;
00120     video_buffer_size = 0;
00121 
00122     act_audio_encode = 0;
00123     act_audio_buffer = 0;
00124     audio_buffer_count = 0;
00125     audio_buffer_size = 0;
00126 
00127     act_text_encode = 0;
00128     act_text_buffer = 0;
00129     text_buffer_count = 0;
00130     text_buffer_size = 0;
00131 
00132     writepaused = false;
00133     audiopaused = false;
00134     mainpaused = false;
00135 
00136     keyframedist = KEYFRAMEDIST;
00137 
00138     audiobytes = 0;
00139     audio_bits = 16;
00140     audio_channels = 2;
00141     audio_samplerate = 44100;
00142     audio_bytes_per_sample = audio_channels * audio_bits / 8;
00143 
00144     picture_format = PIX_FMT_YUV420P;
00145     v4l2_pixelformat = 0;
00146 
00147     avcodec_register_all();
00148 
00149     mpa_vidcodec = 0;
00150     mpa_vidctx = NULL;
00151 
00152     useavcodec = false;
00153 
00154     targetbitrate = 2200;
00155     scalebitrate = 1;
00156     maxquality = 2;
00157     minquality = 31;
00158     qualdiff = 3;
00159     mp4opts = 0;
00160     mb_decision = FF_MB_DECISION_SIMPLE;
00161     encoding_thread_count = 1;
00162 
00163     oldtc = 0;
00164     startnum = 0;
00165     frameofgop = 0;
00166     lasttimecode = 0;
00167     audio_behind = 0;
00168 
00169     extendeddataOffset = 0;
00170     seektable = new vector<struct seektable_entry>;
00171 
00172     hardware_encode = false;
00173     hmjpg_quality = 80;
00174     hmjpg_hdecimation = 2;
00175     hmjpg_vdecimation = 2;
00176     hmjpg_maxw = 640;
00177 
00178     videoFilterList = "";
00179     videoFilters = NULL;
00180     FiltMan = new FilterManager;
00181     inpixfmt = FMT_YV12;
00182     correct_bttv = false;
00183 
00184     usingv4l2 = false;
00185 
00186     prev_bframe_save_pos = -1;
00187 
00188     volume = 100;
00189 
00190     ccd = new CC608Decoder(this);
00191 
00192     go7007 = false;
00193     resetcapture = false;
00194 
00195     SetPositionMapType(MARK_KEYFRAME);
00196 }
00197 
00198 NuppelVideoRecorder::~NuppelVideoRecorder(void)
00199 {
00200     if (weMadeBuffer && ringBuffer)
00201     {
00202         delete ringBuffer;
00203         ringBuffer = NULL;
00204     }
00205     if (rtjc)
00206         delete rtjc;
00207     if (mp3buf)
00208         delete [] mp3buf;
00209     if (gf)
00210         lame_close(gf);
00211     if (strm)
00212         delete [] strm;
00213     if (audio_device)
00214     {
00215         delete audio_device;
00216         audio_device = NULL;
00217     }
00218     if (fd >= 0)
00219         close(fd);
00220     if (seektable)
00221     {
00222         seektable->clear();
00223         delete seektable;
00224     }
00225 
00226     while (videobuffer.size() > 0)
00227     {
00228         struct vidbuffertype *vb = videobuffer.back();
00229         delete [] vb->buffer;
00230         delete vb;
00231         videobuffer.pop_back();
00232     }
00233     while (audiobuffer.size() > 0)
00234     {
00235         struct audbuffertype *ab = audiobuffer.back();
00236         delete [] ab->buffer;
00237         delete ab;
00238         audiobuffer.pop_back();
00239     }
00240     while (textbuffer.size() > 0)
00241     {
00242         struct txtbuffertype *tb = textbuffer.back();
00243         delete [] tb->buffer;
00244         delete tb;
00245         textbuffer.pop_back();
00246     }
00247 
00248     if (mpa_vidcodec)
00249     {
00250         QMutexLocker locker(avcodeclock);
00251         avcodec_close(mpa_vidctx);
00252     }
00253 
00254     if (mpa_vidctx)
00255         av_free(mpa_vidctx);
00256     mpa_vidctx = NULL;
00257 
00258     if (videoFilters)
00259         delete videoFilters;
00260     if (FiltMan)
00261         delete FiltMan;
00262     if (ccd)
00263         delete ccd;
00264 }
00265 
00266 void NuppelVideoRecorder::SetOption(const QString &opt, int value)
00267 {
00268     if (opt == "width")
00269         w_out = width = value;
00270     else if (opt == "height")
00271         h_out = height = value;
00272     else if (opt == "rtjpegchromafilter")
00273         M1 = value;
00274     else if (opt == "rtjpeglumafilter")
00275         M2 = value;
00276     else if (opt == "rtjpegquality")
00277         Q = value;
00278     else if ((opt == "mpeg4bitrate") || (opt == "mpeg2bitrate"))
00279         targetbitrate = value;
00280     else if (opt == "scalebitrate")
00281         scalebitrate = value;
00282     else if (opt == "mpeg4maxquality")
00283     {
00284         if (value > 0)
00285             maxquality = value;
00286         else
00287             maxquality = 1;
00288     }
00289     else if (opt == "mpeg4minquality")
00290         minquality = value;
00291     else if (opt == "mpeg4qualdiff")
00292         qualdiff = value;
00293     else if (opt == "encodingthreadcount")
00294         encoding_thread_count = value;
00295     else if (opt == "mpeg4optionvhq")
00296     {
00297         if (value)
00298             mb_decision = FF_MB_DECISION_RD;
00299         else
00300             mb_decision = FF_MB_DECISION_SIMPLE;
00301     }
00302     else if (opt == "mpeg4option4mv")
00303     {
00304         if (value)
00305             mp4opts |= CODEC_FLAG_4MV;
00306         else
00307             mp4opts &= ~CODEC_FLAG_4MV;
00308     }
00309     else if (opt == "mpeg4optionidct")
00310     {
00311         if (value)
00312             mp4opts |= CODEC_FLAG_INTERLACED_DCT;
00313         else
00314             mp4opts &= ~CODEC_FLAG_INTERLACED_DCT;
00315     }
00316     else if (opt == "mpeg4optionime")
00317     {
00318         if (value)
00319             mp4opts |= CODEC_FLAG_INTERLACED_ME;
00320         else
00321             mp4opts &= ~CODEC_FLAG_INTERLACED_ME;
00322     }
00323     else if (opt == "hardwaremjpegquality")
00324         hmjpg_quality = value;
00325     else if (opt == "hardwaremjpeghdecimation")
00326         hmjpg_hdecimation = value;
00327     else if (opt == "hardwaremjpegvdecimation")
00328         hmjpg_vdecimation = value;
00329     else if (opt == "audiocompression")
00330         compressaudio = value;
00331     else if (opt == "mp3quality")
00332         mp3quality = value;
00333     else if (opt == "samplerate")
00334         audio_samplerate = value;
00335     else if (opt == "audioframesize")
00336         audio_buffer_size = value;
00337     else if (opt == "pip_mode")
00338         pip_mode = value;
00339     else if (opt == "inpixfmt")
00340         inpixfmt = (VideoFrameType)value;
00341     else if (opt == "skipbtaudio")
00342         skip_btaudio = value;
00343     else if (opt == "volume")
00344         volume = value;
00345     else
00346         V4LRecorder::SetOption(opt, value);
00347 }
00348 
00349 void NuppelVideoRecorder::SetOption(const QString &name, const QString &value)
00350 {
00351     V4LRecorder::SetOption(name, value);
00352 }
00353 
00354 void NuppelVideoRecorder::SetOptionsFromProfile(RecordingProfile *profile,
00355                                                 const QString &videodev,
00356                                                 const QString &audiodev,
00357                                                 const QString &vbidev)
00358 {
00359     SetOption("videodevice", videodev);
00360     SetOption("vbidevice", vbidev);
00361     SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
00362     SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
00363     SetOption("audiodevice", audiodev);
00364 
00365     QString setting = QString::null;
00366     const Setting *tmp = profile->byName("videocodec");
00367     if (tmp)
00368         setting = tmp->getValue();
00369 
00370     if (setting == "MPEG-4")
00371     {
00372         SetOption("videocodec", "mpeg4");
00373 
00374         SetIntOption(profile, "mpeg4bitrate");
00375         SetIntOption(profile, "scalebitrate");
00376         SetIntOption(profile, "mpeg4maxquality");
00377         SetIntOption(profile, "mpeg4minquality");
00378         SetIntOption(profile, "mpeg4qualdiff");
00379 #ifdef USING_FFMPEG_THREADS
00380         SetIntOption(profile, "encodingthreadcount");
00381 #endif
00382         SetIntOption(profile, "mpeg4optionvhq");
00383         SetIntOption(profile, "mpeg4option4mv");
00384         SetIntOption(profile, "mpeg4optionidct");
00385         SetIntOption(profile, "mpeg4optionime");
00386     }
00387     else if (setting == "MPEG-2")
00388     {
00389         SetOption("videocodec", "mpeg2video");
00390 
00391         SetIntOption(profile, "mpeg2bitrate");
00392         SetIntOption(profile, "scalebitrate");
00393 #ifdef USING_FFMPEG_THREADS
00394         SetIntOption(profile, "encodingthreadcount");
00395 #endif
00396     }
00397     else if (setting == "RTjpeg")
00398     {
00399         SetOption("videocodec", "rtjpeg");
00400 
00401         SetIntOption(profile, "rtjpegquality");
00402         SetIntOption(profile, "rtjpegchromafilter");
00403         SetIntOption(profile, "rtjpeglumafilter");
00404     }
00405     else if (setting == "Hardware MJPEG")
00406     {
00407         SetOption("videocodec", "hardware-mjpeg");
00408 
00409         SetIntOption(profile, "hardwaremjpegquality");
00410         SetIntOption(profile, "hardwaremjpeghdecimation");
00411         SetIntOption(profile, "hardwaremjpegvdecimation");
00412     }
00413     else
00414     {
00415         LOG(VB_GENERAL, LOG_ERR, LOC +
00416                 "Unknown video codec.  "
00417                 "Please go into the TV Settings, Recording Profiles and "
00418                 "setup the four 'Software Encoders' profiles.  "
00419                 "Assuming RTjpeg for now.");
00420 
00421         SetOption("videocodec", "rtjpeg");
00422 
00423         SetIntOption(profile, "rtjpegquality");
00424         SetIntOption(profile, "rtjpegchromafilter");
00425         SetIntOption(profile, "rtjpeglumafilter");
00426     }
00427 
00428     setting = QString::null;
00429     if ((tmp = profile->byName("audiocodec")))
00430         setting = tmp->getValue();
00431 
00432     if (setting == "MP3")
00433     {
00434         SetOption("audiocompression", 1);
00435         SetIntOption(profile, "mp3quality");
00436         SetIntOption(profile, "samplerate");
00437     }
00438     else if (setting == "Uncompressed")
00439     {
00440         SetOption("audiocompression", 0);
00441         SetIntOption(profile, "samplerate");
00442     }
00443     else
00444     {
00445         LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown audio codec");
00446         SetOption("audiocompression", 0);
00447     }
00448 
00449     SetIntOption(profile, "volume");
00450 
00451     SetIntOption(profile, "width");
00452     SetIntOption(profile, "height");
00453 }
00454 
00455 void NuppelVideoRecorder::Pause(bool clear)
00456 {
00457     QMutexLocker locker(&pauseLock);
00458     cleartimeonpause = clear;
00459     writepaused = audiopaused = mainpaused = false;
00460     request_pause = true;
00461 
00462     // The wakeAll is to make sure [write|audio|main]paused are
00463     // set immediately, even if we were already paused previously.
00464     unpauseWait.wakeAll();
00465 }
00466 
00467 bool NuppelVideoRecorder::IsPaused(bool holding_lock) const
00468 {
00469     if (!holding_lock)
00470         pauseLock.lock();
00471     bool ret = audiopaused && mainpaused && writepaused;
00472     if (!holding_lock)
00473         pauseLock.unlock();
00474     return ret;
00475 }
00476 
00477 void NuppelVideoRecorder::SetVideoFilters(QString &filters)
00478 {
00479     videoFilterList = filters;
00480     InitFilters();
00481 }
00482 
00483 bool NuppelVideoRecorder::IsRecording(void)
00484 {
00485     return recording;
00486 }
00487 
00488 long long NuppelVideoRecorder::GetFramesWritten(void)
00489 {
00490     return framesWritten;
00491 }
00492 
00493 int NuppelVideoRecorder::GetVideoFd(void)
00494 {
00495     return channelfd;
00496 }
00497 
00498 bool NuppelVideoRecorder::SetupAVCodecVideo(void)
00499 {
00500     if (!useavcodec)
00501         useavcodec = true;
00502 
00503     if (mpa_vidcodec)
00504     {
00505         QMutexLocker locker(avcodeclock);
00506         avcodec_close(mpa_vidctx);
00507     }
00508 
00509     if (mpa_vidctx)
00510         av_free(mpa_vidctx);
00511     mpa_vidctx = NULL;
00512 
00513     QByteArray vcodec = videocodec.toAscii();
00514     mpa_vidcodec = avcodec_find_encoder_by_name(vcodec.constData());
00515 
00516     if (!mpa_vidcodec)
00517     {
00518         LOG(VB_GENERAL, LOG_ERR, LOC + QString("Video Codec not found: %1")
00519                 .arg(vcodec.constData()));
00520         return false;
00521     }
00522 
00523     mpa_vidctx = avcodec_alloc_context3(NULL);
00524 
00525     avcodec_get_frame_defaults(&mpa_picture);
00526 
00527     switch (picture_format)
00528     {
00529         case PIX_FMT_YUV420P:
00530         case PIX_FMT_YUV422P:
00531         case PIX_FMT_YUVJ420P:
00532             mpa_vidctx->pix_fmt = picture_format;
00533             mpa_picture.linesize[0] = w_out;
00534             mpa_picture.linesize[1] = w_out / 2;
00535             mpa_picture.linesize[2] = w_out / 2;
00536             break;
00537         default:
00538             LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown picture format: %1")
00539                     .arg(picture_format));
00540     }
00541 
00542     mpa_vidctx->width = w_out;
00543     mpa_vidctx->height = (int)(height * height_multiplier);
00544 
00545     int usebitrate = targetbitrate * 1000;
00546     if (scalebitrate)
00547     {
00548         float diff = (w_out * h_out) / (640.0 * 480.0);
00549         usebitrate = (int)(diff * usebitrate);
00550     }
00551 
00552     if (targetbitrate == -1)
00553         usebitrate = -1;
00554 
00555     mpa_vidctx->time_base.den = (int)ceil(video_frame_rate * 100 *
00556                                     framerate_multiplier);
00557     mpa_vidctx->time_base.num = 100;
00558 
00559     // avcodec needs specific settings for mpeg2 compression
00560     switch (mpa_vidctx->time_base.den)
00561     {
00562         case 2397:
00563         case 2398: mpa_vidctx->time_base.den = 24000;
00564                    mpa_vidctx->time_base.num = 1001;
00565                    break;
00566         case 2997:
00567         case 2998: mpa_vidctx->time_base.den = 30000;
00568                    mpa_vidctx->time_base.num = 1001;
00569                    break;
00570         case 5994:
00571         case 5995: mpa_vidctx->time_base.den = 60000;
00572                    mpa_vidctx->time_base.num = 1001;
00573                    break;
00574     }
00575 
00576     mpa_vidctx->bit_rate = usebitrate;
00577     mpa_vidctx->bit_rate_tolerance = usebitrate * 100;
00578     mpa_vidctx->qmin = maxquality;
00579     mpa_vidctx->qmax = minquality;
00580     mpa_vidctx->max_qdiff = qualdiff;
00581     mpa_vidctx->flags = mp4opts;
00582     mpa_vidctx->mb_decision = mb_decision;
00583 
00584     mpa_vidctx->qblur = 0.5;
00585     mpa_vidctx->max_b_frames = 0;
00586     mpa_vidctx->b_quant_factor = 0;
00587     mpa_vidctx->rc_strategy = 2;
00588     mpa_vidctx->b_frame_strategy = 0;
00589     mpa_vidctx->gop_size = 30;
00590     mpa_vidctx->rc_max_rate = 0;
00591     mpa_vidctx->rc_min_rate = 0;
00592     mpa_vidctx->rc_buffer_size = 0;
00593     mpa_vidctx->rc_buffer_aggressivity = 1.0;
00594     mpa_vidctx->rc_override_count = 0;
00595     mpa_vidctx->rc_initial_cplx = 0;
00596     mpa_vidctx->dct_algo = FF_DCT_AUTO;
00597     mpa_vidctx->idct_algo = FF_IDCT_AUTO;
00598     mpa_vidctx->prediction_method = FF_PRED_LEFT;
00599     if (videocodec.toLower() == "huffyuv" || videocodec.toLower() == "mjpeg")
00600         mpa_vidctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
00601     mpa_vidctx->thread_count = encoding_thread_count;
00602 
00603     QMutexLocker locker(avcodeclock);
00604 
00605     if (avcodec_open2(mpa_vidctx, mpa_vidcodec, NULL) < 0)
00606     {
00607         LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to open FFMPEG/%1 codec")
00608                 .arg(videocodec));
00609         return false;
00610     }
00611 
00612 
00613     return true;
00614 }
00615 
00616 void NuppelVideoRecorder::SetupRTjpeg(void)
00617 {
00618     picture_format = PIX_FMT_YUV420P;
00619 
00620     int setval;
00621     rtjc = new RTjpeg();
00622     setval = RTJ_YUV420;
00623     rtjc->SetFormat(&setval);
00624     setval = (int)(h_out * height_multiplier);
00625     rtjc->SetSize(&w_out, &setval);
00626     rtjc->SetQuality(&Q);
00627     setval = 2;
00628     rtjc->SetIntra(&setval, &M1, &M2);
00629 }
00630 
00631 
00632 void NuppelVideoRecorder::UpdateResolutions(void)
00633 {
00634     int tot_height = (int)(height * height_multiplier);
00635     double aspectnum = w_out / (double)tot_height;
00636     uint aspect;
00637 
00638     if (aspectnum == 0.0)
00639         aspect = 0;
00640     else if (fabs(aspectnum - 1.3333333333333333) < 0.001)
00641         aspect = 2;
00642     else if (fabs(aspectnum - 1.7777777777777777) < 0.001)
00643         aspect = 3;
00644     else if (fabs(aspectnum - 2.21) < 0.001)
00645         aspect = 4;
00646     else
00647         aspect = aspectnum * 1000000;
00648 
00649     if ((aspect > 0) && (aspect != m_videoAspect))
00650     {
00651         m_videoAspect = aspect;
00652         AspectChange((AspectRatio)aspect, 0);
00653     }
00654 
00655     if (w_out && tot_height &&
00656         ((uint)tot_height != m_videoHeight ||
00657          (uint)w_out      != m_videoWidth))
00658     {
00659         m_videoHeight = tot_height;
00660         m_videoWidth = w_out;
00661         ResolutionChange(w_out, tot_height, 0);
00662     }
00663 
00664     int den = (int)ceil(video_frame_rate * 100 * framerate_multiplier);
00665     int num = 100;
00666 
00667     // avcodec needs specific settings for mpeg2 compression
00668     switch (den)
00669     {
00670         case 2397:
00671         case 2398: den = 24000;
00672                    num = 1001;
00673                    break;
00674         case 2997:
00675         case 2998: den = 30000;
00676                    num = 1001;
00677                    break;
00678         case 5994:
00679         case 5995: den = 60000;
00680                    num = 1001;
00681                    break;
00682     }
00683 
00684     uint frameRate = (den * 1000) / num;
00685     if (frameRate && frameRate != m_frameRate)
00686     {
00687         m_frameRate = frameRate;
00688         LOG(VB_RECORD, LOG_INFO, LOC + QString("NVR: frame rate = %1")
00689                 .arg(frameRate));
00690         FrameRateChange(frameRate, 0);
00691     }
00692 }
00693 
00694 void NuppelVideoRecorder::Initialize(void)
00695 {
00696     if (AudioInit() != 0)
00697     {
00698         LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to init audio input device");
00699     }
00700 
00701     if (videocodec == "hardware-mjpeg")
00702     {
00703         videocodec = "mjpeg";
00704         hardware_encode = true;
00705 
00706         MJPEGInit();
00707 
00708         width = hmjpg_maxw / hmjpg_hdecimation;
00709 
00710         if (ntsc)
00711         {
00712             switch (hmjpg_vdecimation)
00713             {
00714                 case 2: height = 240; break;
00715                 case 4: height = 120; break;
00716                 default: height = 480; break;
00717             }
00718         }
00719         else
00720         {
00721             switch (hmjpg_vdecimation)
00722             {
00723                 case 2: height = 288; break;
00724                 case 4: height = 144; break;
00725                 default: height = 576; break;
00726             }
00727         }
00728     }
00729 
00730     if (!ringBuffer)
00731     {
00732         LOG(VB_GENERAL, LOG_WARNING, LOC + "Warning, old RingBuffer creation");
00733         ringBuffer = RingBuffer::Create("output.nuv", true);
00734         weMadeBuffer = true;
00735         livetv = false;
00736         if (!ringBuffer->IsOpen())
00737         {
00738             _error = "Could not open RingBuffer";
00739             LOG(VB_GENERAL, LOG_ERR, LOC + _error);
00740             return;
00741         }
00742     }
00743     else
00744         livetv = ringBuffer->LiveMode();
00745 
00746     audiobytes = 0;
00747 
00748     InitBuffers();
00749     InitFilters();
00750 }
00751 
00752 int NuppelVideoRecorder::AudioInit(bool skipdevice)
00753 {
00754     int blocksize;
00755     int tmp;
00756 
00757     if (!skipdevice)
00758     {
00759         audio_device = AudioInput::CreateDevice(audiodevice.toAscii());
00760         if (!audio_device)
00761         {
00762             LOG(VB_GENERAL, LOG_ERR, LOC +
00763                 QString("Failed to create audio device: %1") .arg(audiodevice));
00764             return 1;
00765         }
00766 
00767         if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
00768         {
00769             LOG(VB_GENERAL, LOG_ERR, LOC +
00770                 QString("Failed to open audio device %1").arg(audiodevice));
00771             return 1;
00772         }
00773 
00774         if ((blocksize = audio_device->GetBlockSize()) <= 0)
00775         {
00776             blocksize = 1024;
00777             LOG(VB_GENERAL, LOG_ERR, LOC +
00778                 QString("Failed to determine audio block size on %1,"
00779                         "using default 1024 bytes").arg(audiodevice));
00780         }
00781 
00782         audio_device->Close();
00783         audio_buffer_size = blocksize;
00784     }
00785 
00786     audio_bytes_per_sample = audio_channels * audio_bits / 8;
00787     LOG(VB_AUDIO, LOG_INFO, LOC +
00788         QString("Audio device %1 buffer size: %1 bytes")
00789             .arg(audio_buffer_size));
00790 
00791     if (compressaudio)
00792     {
00793         gf = lame_init();
00794         lame_set_bWriteVbrTag(gf, 0);
00795         lame_set_quality(gf, mp3quality);
00796         lame_set_compression_ratio(gf, 11);
00797         lame_set_mode(gf, audio_channels == 2 ? STEREO : MONO);
00798         lame_set_num_channels(gf, audio_channels);
00799         lame_set_in_samplerate(gf, audio_samplerate);
00800         if ((tmp = lame_init_params(gf)) != 0)
00801         {
00802             LOG(VB_GENERAL, LOG_ERR, LOC +
00803                 QString("AudioInit(): lame_init_params error %1").arg(tmp));
00804             compressaudio = false;
00805         }
00806 
00807         if (audio_bits != 16)
00808         {
00809             LOG(VB_GENERAL, LOG_ERR, LOC +
00810                 "AudioInit(): lame support requires 16bit audio");
00811             compressaudio = false;
00812         }
00813     }
00814     mp3buf_size = (int)(1.25 * 16384 + 7200);
00815     mp3buf = new char[mp3buf_size];
00816 
00817     return 0;
00818 }
00819 
00829 bool NuppelVideoRecorder::MJPEGInit(void)
00830 {
00831 #ifdef USING_V4L1
00832     bool we_opened_fd = false;
00833     int init_fd = fd;
00834     if (init_fd < 0)
00835     {
00836         QByteArray vdevice = videodevice.toAscii();
00837         init_fd = open(vdevice.constData(), O_RDWR);
00838         we_opened_fd = true;
00839 
00840         if (init_fd < 0)
00841         {
00842             LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device" + ENO);
00843             return false;
00844         }
00845     }
00846 
00847     struct video_capability vc;
00848     memset(&vc, 0, sizeof(vc));
00849     int ret = ioctl(init_fd, VIDIOCGCAP, &vc);
00850 
00851     if (ret < 0)
00852         LOG(VB_GENERAL, LOG_ERR, LOC + "Can't query V4L capabilities" + ENO);
00853 
00854     if (we_opened_fd)
00855         close(init_fd);
00856 
00857     if (ret < 0)
00858         return false;
00859 
00860     if (vc.maxwidth != 768 && vc.maxwidth != 640)
00861         vc.maxwidth = 720;
00862 
00863     if (vc.type & VID_TYPE_MJPEG_ENCODER)
00864     {
00865         if (vc.maxwidth >= 768)
00866             hmjpg_maxw = 768;
00867         else if (vc.maxwidth >= 704)
00868             hmjpg_maxw = 704;
00869         else
00870             hmjpg_maxw = 640;
00871         return true;
00872     }
00873 #endif // USING_V4L1
00874 
00875     LOG(VB_GENERAL, LOG_ERR, LOC + "MJPEG not supported by device");
00876     return false;
00877 }
00878 
00879 void NuppelVideoRecorder::InitFilters(void)
00880 {
00881     int btmp = video_buffer_size;
00882     if (videoFilters)
00883         delete videoFilters;
00884 
00885     QString tmpVideoFilterList;
00886 
00887     w_out = width;
00888     h_out = height;
00889     VideoFrameType tmp = FMT_YV12;
00890 
00891     if (correct_bttv && !videoFilterList.contains("adjust"))
00892     {
00893         if (videoFilterList.isEmpty())
00894             tmpVideoFilterList = "adjust";
00895         else
00896             tmpVideoFilterList = "adjust," + videoFilterList;
00897     }
00898     else
00899         tmpVideoFilterList = videoFilterList;
00900 
00901     videoFilters = FiltMan->LoadFilters(tmpVideoFilterList, inpixfmt, tmp,
00902                                         w_out, h_out, btmp);
00903     if (video_buffer_size && btmp != video_buffer_size)
00904     {
00905         video_buffer_size = btmp;
00906         ResizeVideoBuffers();
00907     }
00908 }
00909 
00910 void NuppelVideoRecorder::InitBuffers(void)
00911 {
00912     int videomegs;
00913     int audiomegs = 2;
00914 
00915     if (!video_buffer_size)
00916     {
00917         if (picture_format == PIX_FMT_YUV422P)
00918             video_buffer_size = w_out * h_out * 2;
00919         else
00920             video_buffer_size = w_out * h_out * 3 / 2;
00921     }
00922 
00923     if (width >= 480 || height > 288)
00924         videomegs = 20;
00925     else
00926         videomegs = 12;
00927 
00928     video_buffer_count = (videomegs * 1000 * 1000) / video_buffer_size;
00929 
00930     if (audio_buffer_size != 0)
00931         audio_buffer_count = (audiomegs * 1000 * 1000) / audio_buffer_size;
00932     else
00933         audio_buffer_count = 0;
00934 
00935     text_buffer_size = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
00936     text_buffer_count = video_buffer_count;
00937 
00938     for (int i = 0; i < video_buffer_count; i++)
00939     {
00940         vidbuffertype *vidbuf = new vidbuffertype;
00941         vidbuf->buffer = new unsigned char[video_buffer_size];
00942         vidbuf->sample = 0;
00943         vidbuf->freeToEncode = 0;
00944         vidbuf->freeToBuffer = 1;
00945         vidbuf->bufferlen = 0;
00946         vidbuf->forcekey = 0;
00947 
00948         videobuffer.push_back(vidbuf);
00949     }
00950 
00951     for (int i = 0; i < audio_buffer_count; i++)
00952     {
00953         audbuffertype *audbuf = new audbuffertype;
00954         audbuf->buffer = new unsigned char[audio_buffer_size];
00955         audbuf->sample = 0;
00956         audbuf->freeToEncode = 0;
00957         audbuf->freeToBuffer = 1;
00958 
00959         audiobuffer.push_back(audbuf);
00960     }
00961 
00962     for (int i = 0; i < text_buffer_count; i++)
00963     {
00964         txtbuffertype *txtbuf = new txtbuffertype;
00965         txtbuf->buffer = new unsigned char[text_buffer_size];
00966         txtbuf->freeToEncode = 0;
00967         txtbuf->freeToBuffer = 1;
00968 
00969         textbuffer.push_back(txtbuf);
00970     }
00971 }
00972 
00973 void NuppelVideoRecorder::ResizeVideoBuffers(void)
00974 {
00975     for (unsigned int i = 0; i < videobuffer.size(); i++)
00976     {
00977         delete [] (videobuffer[i]->buffer);
00978         videobuffer[i]->buffer = new unsigned char[video_buffer_size];
00979     }
00980 }
00981 
00982 void NuppelVideoRecorder::StreamAllocate(void)
00983 {
00984     strm = new signed char[width * height * 2 + 10];
00985 }
00986 
00987 bool NuppelVideoRecorder::Open(void)
00988 {
00989     if (channelfd>0)
00990         return true;
00991 
00992     int retries = 0;
00993     QByteArray vdevice = videodevice.toAscii();
00994     fd = open(vdevice.constData(), O_RDWR);
00995     while (fd < 0)
00996     {
00997         usleep(30000);
00998         fd = open(vdevice.constData(), O_RDWR);
00999         if (retries++ > 5)
01000         {
01001             _error = QString("Can't open video device: %1").arg(videodevice);
01002             LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
01003             KillChildren();
01004             return false;
01005         }
01006     }
01007 
01008     channelfd = fd;
01009     return true;
01010 }
01011 
01012 void NuppelVideoRecorder::ProbeV4L2(void)
01013 {
01014 #ifdef USING_V4L2
01015     usingv4l2 = true;
01016 
01017     struct v4l2_capability vcap;
01018     memset(&vcap, 0, sizeof(vcap));
01019 
01020     if (ioctl(channelfd, VIDIOC_QUERYCAP, &vcap) < 0)
01021     {
01022         usingv4l2 = false;
01023     }
01024 
01025     if (usingv4l2 && !(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
01026     {
01027         LOG(VB_GENERAL, LOG_ERR, LOC +
01028             "Not a v4l2 capture device, falling back to v4l");
01029         usingv4l2 = false;
01030     }
01031 
01032     if (usingv4l2 && !(vcap.capabilities & V4L2_CAP_STREAMING))
01033     {
01034         LOG(VB_GENERAL, LOG_ERR, LOC +
01035             "Won't work with the streaming interface, falling back");
01036         usingv4l2 = false;
01037     }
01038 
01039     if (vcap.card[0] == 'B' && vcap.card[1] == 'T' &&
01040         vcap.card[2] == '8' && vcap.card[4] == '8')
01041         correct_bttv = true;
01042 
01043     QString driver = (char *)vcap.driver;
01044     if (driver == "go7007")
01045         go7007 = true;
01046 #endif // USING_V4L2
01047 }
01048 
01049 void NuppelVideoRecorder::run(void)
01050 {
01051     if (lzo_init() != LZO_E_OK)
01052     {
01053         LOG(VB_GENERAL, LOG_ERR, LOC + "lzo_init() failed, exiting");
01054         _error = "lzo_init() failed, exiting";
01055         LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01056         return;
01057     }
01058 
01059     if (!Open())
01060     {
01061         _error = "Failed to open device";
01062         LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01063         return;
01064     }
01065 
01066     ProbeV4L2();
01067 
01068     if (usingv4l2 && !SetFormatV4L2())
01069     {
01070         _error = "Failed to set V4L2 format";
01071         LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01072         return;
01073     }
01074 
01075     StreamAllocate();
01076 
01077     positionMapLock.lock();
01078     positionMap.clear();
01079     positionMapDelta.clear();
01080     positionMapLock.unlock();
01081 
01082     if (videocodec.toLower() == "rtjpeg")
01083         useavcodec = false;
01084     else
01085         useavcodec = true;
01086 
01087     if (useavcodec)
01088         useavcodec = SetupAVCodecVideo();
01089 
01090     if (!useavcodec)
01091         SetupRTjpeg();
01092 
01093     UpdateResolutions();
01094 
01095     if (CreateNuppelFile() != 0)
01096     {
01097         _error = QString("Cannot open '%1' for writing")
01098             .arg(ringBuffer->GetFilename());
01099         LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01100         return;
01101     }
01102 
01103     if (IsHelperRequested())
01104     {
01105         LOG(VB_GENERAL, LOG_ERR, LOC + "Children are already alive");
01106         _error = "Children are already alive";
01107         return;
01108     }
01109 
01110     {
01111         QMutexLocker locker(&pauseLock);
01112         request_recording = true;
01113         request_helper = true;
01114         recording = true;
01115         recordingWait.wakeAll();
01116     }
01117 
01118     write_thread = new NVRWriteThread(this);
01119     write_thread->start();
01120 
01121     audio_thread = new NVRAudioThread(this);
01122     audio_thread->start();
01123 
01124     if ((vbimode != VBIMode::None) && (OpenVBIDevice() >= 0))
01125         vbi_thread = new VBIThread(this);
01126 
01127     // save the start time
01128     gettimeofday(&stm, &tzone);
01129 
01130     // try to get run at higher scheduling priority, ignore failure
01131     myth_nice(-10);
01132 
01133     if (usingv4l2)
01134     {
01135         inpixfmt = FMT_NONE;
01136         InitFilters();
01137         DoV4L2();
01138     }
01139     else
01140         DoV4L1();
01141 
01142     {
01143         QMutexLocker locker(&pauseLock);
01144         request_recording = false;
01145         request_helper = false;
01146         recording = false;
01147         recordingWait.wakeAll();
01148     }
01149 }
01150 
01151 #ifdef USING_V4L1
01152 void NuppelVideoRecorder::DoV4L1(void)
01153 {
01154     struct video_capability vc;
01155     struct video_mmap mm;
01156     struct video_mbuf vm;
01157     struct video_channel vchan;
01158     struct video_audio va;
01159     struct video_tuner vt;
01160 
01161     memset(&mm, 0, sizeof(mm));
01162     memset(&vm, 0, sizeof(vm));
01163     memset(&vchan, 0, sizeof(vchan));
01164     memset(&va, 0, sizeof(va));
01165     memset(&vt, 0, sizeof(vt));
01166     memset(&vc, 0, sizeof(vc));
01167 
01168     if (ioctl(fd, VIDIOCGCAP, &vc) < 0)
01169     {
01170         QString tmp = "VIDIOCGCAP: " + ENO;
01171         KillChildren();
01172         LOG(VB_GENERAL, LOG_ERR, tmp);
01173         _error = tmp;
01174         return;
01175     }
01176 
01177     int channelinput = 0;
01178 
01179     if (channelObj)
01180         channelinput = channelObj->GetCurrentInputNum();
01181 
01182     vchan.channel = channelinput;
01183 
01184     if (ioctl(fd, VIDIOCGCHAN, &vchan) < 0)
01185         LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCGCHAN: " + ENO);
01186 
01187     // Set volume level for audio recording (unless feature is disabled).
01188     if (!skip_btaudio)
01189     {
01190         // v4l1 compat in Linux 2.6.18 does not set VIDEO_VC_AUDIO,
01191         // so we just use VIDIOCGAUDIO unconditionally.. then only
01192         // report a get failure as an error if VIDEO_VC_AUDIO is set.
01193         if (ioctl(fd, VIDIOCGAUDIO, &va) < 0)
01194         {
01195             bool reports_audio = vchan.flags & VIDEO_VC_AUDIO;
01196             uint err_level = reports_audio ? VB_GENERAL : VB_AUDIO;
01197             // print at VB_GENERAL if driver reports audio.
01198             LOG(err_level, LOG_ERR, LOC + "Failed to get audio" + ENO);
01199         }
01200         else
01201         {
01202             // if channel has a audio then activate it
01203             va.flags &= ~VIDEO_AUDIO_MUTE; // now this really has to work
01204             va.volume = volume * 65535 / 100;
01205             if (ioctl(fd, VIDIOCSAUDIO, &va) < 0)
01206                 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set audio" + ENO);
01207         }
01208     }
01209 
01210     if ((vc.type & VID_TYPE_MJPEG_ENCODER) && hardware_encode)
01211     {
01212         DoMJPEG();
01213         _error = "MJPEG requested but not available.";
01214         LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01215         return;
01216     }
01217 
01218     inpixfmt = FMT_NONE;
01219     InitFilters();
01220 
01221     if (ioctl(fd, VIDIOCGMBUF, &vm) < 0)
01222     {
01223         QString tmp = "VIDIOCGMBUF: " + ENO;
01224         KillChildren();
01225         LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
01226         _error = tmp;
01227         return;
01228     }
01229 
01230     if (vm.frames < 2)
01231     {
01232         QString tmp = "need a minimum of 2 capture buffers";
01233         KillChildren();
01234         LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
01235         _error = tmp;
01236         return;
01237     }
01238 
01239     int frame;
01240 
01241     unsigned char *buf = (unsigned char *)mmap(0, vm.size,
01242                                                PROT_READ|PROT_WRITE,
01243                                                MAP_SHARED,
01244                                                fd, 0);
01245     if (buf <= 0)
01246     {
01247         QString tmp = "mmap: " + ENO;
01248         KillChildren();
01249         LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
01250         _error = tmp;
01251         return;
01252     }
01253 
01254     mm.height = height;
01255     mm.width  = width;
01256     if (inpixfmt == FMT_YUV422P)
01257         mm.format = VIDEO_PALETTE_YUV422P;
01258     else
01259         mm.format = VIDEO_PALETTE_YUV420P;
01260 
01261     mm.frame  = 0;
01262     if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01263         LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTUREi0: " + ENO);
01264     mm.frame  = 1;
01265     if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01266         LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTUREi1: " + ENO);
01267 
01268     int syncerrors = 0;
01269 
01270     while (IsRecordingRequested() && !IsErrored())
01271     {
01272         {
01273             QMutexLocker locker(&pauseLock);
01274             if (request_pause)
01275             {
01276                 if (!mainpaused)
01277                 {
01278                     mainpaused = true;
01279                     pauseWait.wakeAll();
01280                     if (IsPaused(true) && tvrec)
01281                         tvrec->RecorderPaused();
01282                 }
01283                 unpauseWait.wait(&pauseLock, 100);
01284                 if (cleartimeonpause)
01285                     gettimeofday(&stm, &tzone);
01286                 continue;
01287             }
01288             
01289             if (!request_pause && mainpaused)
01290             {
01291                 mainpaused = false;
01292                 unpauseWait.wakeAll();
01293             }
01294         }
01295 
01296         frame = 0;
01297         mm.frame = 0;
01298         if (ioctl(fd, VIDIOCSYNC, &frame)<0)
01299         {
01300             syncerrors++;
01301             if (syncerrors == 10)
01302                 LOG(VB_GENERAL, LOG_ERR, LOC +
01303                     "Multiple bttv errors, further messages supressed");
01304             else if (syncerrors < 10)
01305                 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCSYNC: " + ENO);
01306         }
01307         else
01308         {
01309             BufferIt(buf+vm.offsets[0], video_buffer_size);
01310             //memset(buf+vm.offsets[0], 0, video_buffer_size);
01311         }
01312 
01313         if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01314             LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTURE0: " + ENO);
01315 
01316         frame = 1;
01317         mm.frame = 1;
01318         if (ioctl(fd, VIDIOCSYNC, &frame)<0)
01319         {
01320             syncerrors++;
01321             if (syncerrors == 10)
01322                 LOG(VB_GENERAL, LOG_ERR, LOC +
01323                     "Multiple bttv errors, further messages supressed");
01324             else if (syncerrors < 10)
01325                 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCSYNC: " + ENO);
01326         }
01327         else
01328         {
01329             BufferIt(buf+vm.offsets[1], video_buffer_size);
01330             //memset(buf+vm.offsets[1], 0, video_buffer_size);
01331         }
01332         if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01333             LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTURE1: " + ENO);
01334     }
01335 
01336     munmap(buf, vm.size);
01337 
01338     KillChildren();
01339 
01340     FinishRecording();
01341 
01342     close(fd);
01343 }
01344 #else // if !USING_V4L1
01345 void NuppelVideoRecorder::DoV4L1(void) {}
01346 #endif // !USING_V4L1
01347 
01348 #ifdef USING_V4L2
01349 bool NuppelVideoRecorder::SetFormatV4L2(void)
01350 {
01351     struct v4l2_format     vfmt;
01352     memset(&vfmt, 0, sizeof(vfmt));
01353 
01354     vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01355 
01356     vfmt.fmt.pix.width = width;
01357     vfmt.fmt.pix.height = height;
01358     vfmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
01359 
01360     if (go7007)
01361         vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
01362     else if (inpixfmt == FMT_YUV422P)
01363         vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
01364     else
01365         vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
01366 
01367     if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
01368     {
01369         // this is supported by the cx88 and various ati cards.
01370         vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
01371 
01372         if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
01373         {
01374             // this is supported by the HVR-950q
01375             vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
01376             if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
01377             {
01378                 LOG(VB_GENERAL, LOG_ERR, LOC +
01379                     "v4l2: Unable to set desired format");
01380                 return false;
01381             }
01382             else
01383             {
01384                 // we need to convert the buffer - we can't deal with uyvy 
01385                 // directly.
01386                 if (inpixfmt == FMT_YUV422P)
01387                 {
01388                     LOG(VB_GENERAL, LOG_ERR, LOC +
01389                         "v4l2: uyvy format supported, but yuv422 requested.");
01390                     LOG(VB_GENERAL, LOG_ERR, LOC +
01391                         "v4l2: unfortunately, this converter hasn't been "
01392                         "written yet, exiting");
01393                     return false;
01394                 }
01395                 LOG(VB_RECORD, LOG_INFO, LOC +
01396                     "v4l2: format set, getting uyvy from v4l, converting");
01397             }
01398         }
01399         else
01400         {
01401             // we need to convert the buffer - we can't deal with yuyv directly.
01402             if (inpixfmt == FMT_YUV422P)
01403             {
01404                 LOG(VB_GENERAL, LOG_ERR, LOC +
01405                     "v4l2: yuyv format supported, but yuv422 requested.");
01406                 LOG(VB_GENERAL, LOG_ERR, LOC +
01407                     "v4l2: unfortunately, this converter hasn't been written "
01408                     "yet, exiting");
01409                 return false;
01410             }
01411             LOG(VB_RECORD, LOG_INFO, LOC +
01412                 "v4l2: format set, getting yuyv from v4l, converting");
01413         }
01414     }
01415     else // cool, we can do our preferred format, most likely running on bttv.
01416         LOG(VB_RECORD, LOG_INFO, LOC +
01417             "v4l2: format set, getting yuv420 from v4l");
01418 
01419     // VIDIOC_S_FMT might change the format, check it
01420     if (width  != (int)vfmt.fmt.pix.width ||
01421         height != (int)vfmt.fmt.pix.height)
01422     {
01423         LOG(VB_RECORD, LOG_INFO, LOC +
01424             QString("v4l2: resolution changed. requested %1x%2, using "
01425                     "%3x%4 now")
01426                 .arg(width).arg(height)
01427                 .arg(vfmt.fmt.pix.width) .arg(vfmt.fmt.pix.height));
01428         w_out = width  = vfmt.fmt.pix.width;
01429         h_out = height = vfmt.fmt.pix.height;
01430     }
01431 
01432     v4l2_pixelformat = vfmt.fmt.pix.pixelformat;
01433 
01434     return true;
01435 }
01436 #else // if !USING_V4L2
01437 bool NuppelVideoRecorder::SetFormatV4L2(void) { return false; }
01438 #endif // !USING_V4L2
01439 
01440 #ifdef USING_V4L2
01441 #define MAX_VIDEO_BUFFERS 5
01442 void NuppelVideoRecorder::DoV4L2(void)
01443 {
01444     struct v4l2_buffer     vbuf;
01445     struct v4l2_requestbuffers vrbuf;
01446     struct v4l2_control    vc;
01447 
01448     memset(&vbuf, 0, sizeof(vbuf));
01449     memset(&vrbuf, 0, sizeof(vrbuf));
01450     memset(&vc, 0, sizeof(vc));
01451 
01452     vc.id = V4L2_CID_AUDIO_MUTE;
01453     vc.value = 0;
01454 
01455     if (ioctl(fd, VIDIOC_S_CTRL, &vc) < 0)
01456         LOG(VB_GENERAL, LOG_ERR, LOC +
01457             "VIDIOC_S_CTRL:V4L2_CID_AUDIO_MUTE: " + ENO);
01458 
01459     if (go7007)
01460     {
01461         struct go7007_comp_params comp;
01462         struct go7007_mpeg_params mpeg;
01463 
01464         memset(&comp, 0, sizeof(comp));
01465         comp.gop_size = keyframedist;
01466         comp.max_b_frames = 0;
01467 
01468         if (fabs(video_aspect - 1.33333) < 0.01f)
01469         {
01470             if (ntsc)
01471                 comp.aspect_ratio = GO7007_ASPECT_RATIO_4_3_NTSC;
01472             else
01473                 comp.aspect_ratio = GO7007_ASPECT_RATIO_4_3_PAL;
01474         }
01475         else if (fabs(video_aspect - 1.77777) < 0.01f)
01476         {
01477             if (ntsc)
01478                 comp.aspect_ratio = GO7007_ASPECT_RATIO_16_9_NTSC;
01479             else
01480                 comp.aspect_ratio = GO7007_ASPECT_RATIO_16_9_PAL;
01481         }
01482         else
01483         {
01484             comp.aspect_ratio = GO7007_ASPECT_RATIO_1_1;
01485         }
01486 
01487         comp.flags |= GO7007_COMP_CLOSED_GOP;
01488         if (ioctl(fd, GO7007IOC_S_COMP_PARAMS, &comp) < 0)
01489         {
01490             _error = "Unable to set compression params";
01491             LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01492             return;
01493         }
01494 
01495         memset(&mpeg, 0, sizeof(mpeg));
01496 
01497         if (videocodec == "mpeg2video")
01498             mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
01499         else
01500             mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
01501 
01502         if (ioctl(fd, GO7007IOC_S_MPEG_PARAMS, &mpeg) < 0)
01503         {
01504             _error = "Unable to set MPEG params";
01505             LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01506             return;
01507         }
01508 
01509         int usebitrate = targetbitrate * 1000;
01510         if (scalebitrate)
01511         {
01512             float diff = (width * height) / (640.0 * 480.0);
01513             usebitrate = (int)(diff * usebitrate);
01514         }
01515 
01516         if (ioctl(fd, GO7007IOC_S_BITRATE, &usebitrate) < 0)
01517         {
01518             _error = "Unable to set bitrate";
01519             LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01520             return;
01521         }
01522 
01523         hardware_encode = true;
01524     }
01525 
01526     uint numbuffers = MAX_VIDEO_BUFFERS;
01527 
01528     vrbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01529     vrbuf.memory = V4L2_MEMORY_MMAP;
01530     vrbuf.count = numbuffers;
01531 
01532     if (ioctl(fd, VIDIOC_REQBUFS, &vrbuf) < 0)
01533     {
01534         _error = "Not able to get any capture buffers, exiting";
01535         LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01536         return;
01537     }
01538 
01539     if (vrbuf.count < numbuffers)
01540     {
01541         LOG(VB_GENERAL, LOG_INFO, LOC +
01542             QString("Requested %1 buffers, but only %2 are available. "
01543                     "Proceeding anyway").arg(numbuffers).arg(vrbuf.count));
01544     }
01545 
01546     numbuffers = vrbuf.count;
01547 
01548     unsigned char *buffers[MAX_VIDEO_BUFFERS];
01549     int bufferlen[MAX_VIDEO_BUFFERS];
01550 
01551     for (uint i = 0; i < numbuffers; i++)
01552     {
01553         vbuf.type = vrbuf.type;
01554         vbuf.index = i;
01555 
01556         if (ioctl(fd, VIDIOC_QUERYBUF, &vbuf) < 0)
01557         {
01558             LOG(VB_GENERAL, LOG_ERR, LOC +
01559                 QString("unable to query capture buffer %1").arg(i));
01560             _error = "Unable to query capture buffer";
01561             return;
01562         }
01563 
01564         buffers[i] = (unsigned char *)mmap(NULL, vbuf.length,
01565                                            PROT_READ|PROT_WRITE, MAP_SHARED,
01566                                            fd, vbuf.m.offset);
01567 
01568         if (buffers[i] == MAP_FAILED)
01569         {
01570             LOG(VB_GENERAL, LOG_ERR, LOC + "mmap: " + ENO);
01571             LOG(VB_GENERAL, LOG_ERR, LOC + "Memory map failed");
01572             _error = "Memory map failed";
01573             return;
01574         }
01575         bufferlen[i] = vbuf.length;
01576     }
01577 
01578     for (uint i = 0; i < numbuffers; i++)
01579     {
01580         memset(buffers[i], 0, bufferlen[i]);
01581         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01582         vbuf.index = i;
01583         ioctl(fd, VIDIOC_QBUF, &vbuf);
01584     }
01585 
01586     int turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01587     ioctl(fd, VIDIOC_STREAMON, &turnon);
01588 
01589     struct timeval tv;
01590     fd_set rdset;
01591     int frame = 0;
01592     bool forcekey = false;
01593 
01594     resetcapture = false;
01595 
01596     // setup pixel format conversions for YUYV and UYVY
01597     uint8_t *output_buffer = NULL;
01598     struct SwsContext *convert_ctx = NULL;
01599     AVPicture img_out;
01600     if (v4l2_pixelformat == V4L2_PIX_FMT_YUYV ||
01601         v4l2_pixelformat == V4L2_PIX_FMT_UYVY)
01602     {
01603         PixelFormat in_pixfmt = v4l2_pixelformat == V4L2_PIX_FMT_YUYV ?
01604                                 PIX_FMT_YUYV422 :
01605                                 PIX_FMT_UYVY422;
01606 
01607         output_buffer = (uint8_t*)av_malloc(height * width * 3 / 2);
01608         if (!output_buffer)
01609         {
01610             _error = "Cannot initialize image conversion buffer";
01611             LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01612             return;
01613         }
01614 
01615         convert_ctx = sws_getCachedContext(convert_ctx, width, height, in_pixfmt,
01616                                            width, height, PIX_FMT_YUV420P,
01617                                            SWS_FAST_BILINEAR, NULL, NULL, NULL);
01618         if (!convert_ctx)
01619         {
01620             _error = "Cannot initialize image conversion context";
01621             LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01622             return;
01623         }
01624 
01625         avpicture_fill(&img_out, output_buffer, PIX_FMT_YUV420P, width, height);
01626     }
01627 
01628     while (IsRecordingRequested() && !IsErrored())
01629     {
01630 again:
01631         {
01632             QMutexLocker locker(&pauseLock);
01633             if (request_pause)
01634             {
01635                 if (!mainpaused)
01636                 {
01637                     mainpaused = true;
01638                     pauseWait.wakeAll();
01639                     if (IsPaused(true) && tvrec)
01640                         tvrec->RecorderPaused();
01641                 }
01642                 unpauseWait.wait(&pauseLock, 100);
01643                 if (cleartimeonpause)
01644                     gettimeofday(&stm, &tzone);
01645                 continue;
01646             }
01647             
01648             if (!request_pause && mainpaused)
01649             {
01650                 mainpaused = false;
01651                 unpauseWait.wakeAll();
01652             }
01653         }
01654 
01655         if (resetcapture)
01656         {
01657             LOG(VB_GENERAL, LOG_ERR, LOC + "Resetting and re-queueing");
01658             turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01659             ioctl(fd, VIDIOC_STREAMOFF, &turnon);
01660 
01661             for (uint i = 0; i < numbuffers; i++)
01662             {
01663                 memset(buffers[i], 0, bufferlen[i]);
01664                 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01665                 vbuf.index = i;
01666                 ioctl(fd, VIDIOC_QBUF, &vbuf);
01667              }
01668 
01669              ioctl(fd, VIDIOC_STREAMON, &turnon);
01670              resetcapture = false;
01671         }
01672 
01673         tv.tv_sec = 5;
01674         tv.tv_usec = 0;
01675         FD_ZERO(&rdset);
01676         FD_SET(fd, &rdset);
01677 
01678         switch (select(fd+1, &rdset, NULL, NULL, &tv))
01679         {
01680             case -1:
01681                   if (errno == EINTR)
01682                       goto again;
01683                   LOG(VB_GENERAL, LOG_ERR, LOC + "select: " + ENO);
01684                   continue;
01685             case 0:
01686                   LOG(VB_GENERAL, LOG_INFO, LOC + "select timeout");
01687                   continue;
01688            default: break;
01689         }
01690 
01691         memset(&vbuf, 0, sizeof(vbuf));
01692         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01693         vbuf.memory = V4L2_MEMORY_MMAP;
01694         if (ioctl(fd, VIDIOC_DQBUF, &vbuf) < 0)
01695         {
01696             LOG(VB_GENERAL, LOG_ERR, LOC + "DQBUF ioctl failed." + ENO);
01697 
01698             // EIO failed DQBUF de-tunes post 2.6.15.3 for cx88
01699             // EIO or EINVAL on bttv means we need to reset the buffers..
01700             if (errno == EIO && channelObj)
01701             {
01702                 channelObj->Retune();
01703                 resetcapture = true;
01704                 continue;
01705             }
01706 
01707             if (errno == EIO || errno == EINVAL)
01708             {
01709                 resetcapture = true;
01710                 continue;
01711             }
01712 
01713             if (errno == EAGAIN)
01714                 continue;
01715         }
01716 
01717         frame = vbuf.index;
01718         if (go7007)
01719             forcekey = vbuf.flags & V4L2_BUF_FLAG_KEYFRAME;
01720 
01721         if (!request_pause)
01722         {
01723             if (v4l2_pixelformat == V4L2_PIX_FMT_YUYV)
01724             {
01725                 AVPicture img_in;
01726                 avpicture_fill(&img_in, buffers[frame], PIX_FMT_YUYV422, width, height);
01727                 sws_scale(convert_ctx, img_in.data, img_in.linesize,
01728                           0, height, img_out.data, img_out.linesize);
01729                 BufferIt(output_buffer, video_buffer_size);
01730             }
01731             else if (v4l2_pixelformat == V4L2_PIX_FMT_UYVY)
01732             {
01733                 AVPicture img_in;
01734                 avpicture_fill(&img_in, buffers[frame], PIX_FMT_UYVY422, width, height);
01735                 sws_scale(convert_ctx, img_in.data, img_in.linesize,
01736                           0, height, img_out.data, img_out.linesize);
01737                 BufferIt(output_buffer, video_buffer_size);
01738             }
01739             else
01740             {
01741                 // buffer the frame directly
01742                 BufferIt(buffers[frame], vbuf.bytesused, forcekey);
01743             }
01744         }
01745 
01746         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01747         ioctl(fd, VIDIOC_QBUF, &vbuf);
01748     }
01749 
01750     KillChildren();
01751 
01752     ioctl(fd, VIDIOC_STREAMOFF, &turnon);
01753 
01754     for (uint i = 0; i < numbuffers; i++)
01755     {
01756         munmap(buffers[i], bufferlen[i]);
01757     }
01758 
01759     FinishRecording();
01760 
01761     av_free(output_buffer);
01762     sws_freeContext(convert_ctx);
01763 
01764     close(fd);
01765     close(channelfd);
01766 }
01767 #else // if !USING_V4L2
01768 void NuppelVideoRecorder::DoV4L2(void) {}
01769 #endif // !USING_V4L2
01770 
01771 #ifdef USING_V4L1
01772 void NuppelVideoRecorder::DoMJPEG(void)
01773 {
01774     struct mjpeg_params bparm;
01775 
01776     if (ioctl(fd, MJPIOC_G_PARAMS, &bparm) < 0)
01777     {
01778         LOG(VB_GENERAL, LOG_ERR, LOC + "MJPIOC_G_PARAMS: " + ENO);
01779         return;
01780     }
01781 
01782     //bparm.input = 2;
01783     //bparm.norm = 1;
01784     bparm.quality = hmjpg_quality;
01785 
01786     if (hmjpg_hdecimation == hmjpg_vdecimation)
01787     {
01788         bparm.decimation = hmjpg_hdecimation;
01789     }
01790     else
01791     {
01792         bparm.decimation = 0;
01793         bparm.HorDcm = hmjpg_hdecimation;
01794         bparm.VerDcm = (hmjpg_vdecimation + 1) / 2;
01795 
01796         if (hmjpg_vdecimation == 1)
01797         {
01798             bparm.TmpDcm = 1;
01799             bparm.field_per_buff = 2;
01800         }
01801         else
01802         {
01803             bparm.TmpDcm = 2;
01804             bparm.field_per_buff = 1;
01805         }
01806 
01807         bparm.img_width = hmjpg_maxw;
01808 
01809         if (ntsc)
01810             bparm.img_height = 240;
01811         else
01812             bparm.img_height = 288;
01813 
01814         bparm.img_x = 0;
01815         bparm.img_y = 0;
01816     }
01817 
01818     bparm.APPn = 0;
01819 
01820     if (hmjpg_vdecimation == 1)
01821         bparm.APP_len = 14;
01822     else
01823         bparm.APP_len = 0;
01824 
01825     bparm.odd_even = !(hmjpg_vdecimation > 1);
01826 
01827     for (int n = 0; n < bparm.APP_len; n++)
01828         bparm.APP_data[n] = 0;
01829 
01830     if (ioctl(fd, MJPIOC_S_PARAMS, &bparm) < 0)
01831     {
01832         LOG(VB_GENERAL, LOG_DEBUG, LOC + "MJPIOC_S_PARAMS: " + ENO);
01833         return;
01834     }
01835 
01836     struct mjpeg_requestbuffers breq;
01837 
01838     breq.count = 64;
01839     breq.size = 256 * 1024;
01840 
01841     if (ioctl(fd, MJPIOC_REQBUFS, &breq) < 0)
01842     {
01843         LOG(VB_GENERAL, LOG_DEBUG, LOC + "MJPIOC_REQBUFS: " + ENO);
01844         return;
01845     }
01846 
01847     uint8_t *MJPG_buff = (uint8_t *)mmap(0, breq.count * breq.size,
01848                                          PROT_READ|PROT_WRITE, MAP_SHARED, fd,
01849                                          0);
01850 
01851     if (MJPG_buff == MAP_FAILED)
01852     {
01853         LOG(VB_GENERAL, LOG_ERR, LOC + "mapping mjpeg buffers");
01854         return;
01855     }
01856 
01857     struct mjpeg_sync bsync;
01858 
01859     for (unsigned int count = 0; count < breq.count; count++)
01860     {
01861         if (ioctl(fd, MJPIOC_QBUF_CAPT, &count) < 0)
01862             LOG(VB_GENERAL, LOG_ERR, LOC + "MJPIOC_QBUF_CAPT: " + ENO);
01863     }
01864 
01865     while (IsRecordingRequested() && !IsErrored())
01866     {
01867         {
01868             QMutexLocker locker(&pauseLock);
01869             if (request_pause)
01870             {
01871                 if (!mainpaused)
01872                 {
01873                     mainpaused = true;
01874                     pauseWait.wakeAll();
01875                     if (IsPaused(true) && tvrec)
01876                         tvrec->RecorderPaused();
01877                 }
01878                 unpauseWait.wait(&pauseLock, 100);
01879                 if (cleartimeonpause)
01880                     gettimeofday(&stm, &tzone);
01881                 continue;
01882             }
01883             
01884             if (!request_pause && mainpaused)
01885             {
01886                 mainpaused = false;
01887                 unpauseWait.wakeAll();
01888             }
01889         }
01890 
01891         if (ioctl(fd, MJPIOC_SYNC, &bsync) < 0)
01892         {
01893             _error = "MJPEG sync error";
01894             LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
01895             break;
01896         }
01897 
01898         BufferIt((unsigned char *)(MJPG_buff + bsync.frame * breq.size),
01899                  bsync.length);
01900 
01901         if (ioctl(fd, MJPIOC_QBUF_CAPT, &(bsync.frame)) < 0)
01902         {
01903             _error = "MJPEG Capture error";
01904             LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
01905         }
01906     }
01907 
01908     munmap(MJPG_buff, breq.count * breq.size);
01909     KillChildren();
01910 
01911     FinishRecording();
01912 
01913     close(fd);
01914 }
01915 #else // if !USING_V4L1
01916 void NuppelVideoRecorder::DoMJPEG(void) {}
01917 #endif // !USING_V4L1
01918 
01919 void NuppelVideoRecorder::KillChildren(void)
01920 {
01921     {
01922         QMutexLocker locker(&pauseLock);
01923         request_helper = false;
01924         unpauseWait.wakeAll();
01925     }
01926 
01927     if (write_thread)
01928     {
01929         write_thread->wait();
01930         delete write_thread;
01931         write_thread = NULL;
01932     }
01933 
01934     if (audio_thread)
01935     {
01936         audio_thread->wait();
01937         delete audio_thread;
01938         audio_thread = NULL;
01939     }
01940 
01941     if (vbi_thread)
01942     {
01943         vbi_thread->wait();
01944         delete vbi_thread;
01945         vbi_thread = NULL;
01946         CloseVBIDevice();
01947     }
01948 }
01949 
01950 void NuppelVideoRecorder::BufferIt(unsigned char *buf, int len, bool forcekey)
01951 {
01952     int act;
01953     long tcres;
01954     int fn;
01955     struct timeval now;
01956 
01957     act = act_video_buffer;
01958 
01959     if (!videobuffer[act]->freeToBuffer) {
01960         return;
01961     }
01962 
01963     gettimeofday(&now, &tzone);
01964 
01965     tcres = (now.tv_sec-stm.tv_sec)*1000 + now.tv_usec/1000 - stm.tv_usec/1000;
01966 
01967     usebttv = 0;
01968     // here is the non preferable timecode - drop algorithm - fallback
01969     if (!usebttv)
01970     {
01971         if (tf==0)
01972             tf = 2;
01973         else
01974         {
01975             fn = tcres - oldtc;
01976 
01977      // the difference should be less than 1,5*timeperframe or we have
01978      // missed at least one frame, this code might be inaccurate!
01979 
01980             if (ntsc_framerate)
01981                 fn = (fn+16)/33;
01982             else
01983                 fn = (fn+20)/40;
01984             if (fn<1)
01985                 fn=1;
01986             tf += 2*fn; // two fields
01987         }
01988     }
01989 
01990     oldtc = tcres;
01991 
01992     if (!videobuffer[act]->freeToBuffer)
01993     {
01994         LOG(VB_GENERAL, LOG_INFO, LOC +
01995             "DROPPED frame due to full buffer in the recorder.");
01996         return; // we can't buffer the current frame
01997     }
01998 
01999     videobuffer[act]->sample = tf;
02000 
02001     // record the time at the start of this frame.
02002     // 'tcres' is at the end of the frame, so subtract the right # of ms
02003     videobuffer[act]->timecode = (ntsc_framerate) ? (tcres - 33) : (tcres - 40);
02004 
02005     memcpy(videobuffer[act]->buffer, buf, len);
02006     videobuffer[act]->bufferlen = len;
02007     videobuffer[act]->forcekey = forcekey;
02008 
02009     videobuffer[act]->freeToBuffer = 0;
02010     act_video_buffer++;
02011     if (act_video_buffer >= video_buffer_count)
02012         act_video_buffer = 0; // cycle to begin of buffer
02013     videobuffer[act]->freeToEncode = 1; // set last to prevent race
02014     return;
02015 }
02016 
02017 inline void NuppelVideoRecorder::WriteFrameheader(rtframeheader *fh)
02018 {
02019 #if HAVE_BIGENDIAN
02020     fh->timecode     = bswap_32(fh->timecode);
02021     fh->packetlength = bswap_32(fh->packetlength);
02022 #endif
02023     ringBuffer->Write(fh, FRAMEHEADERSIZE);
02024 }
02025 
02026 void NuppelVideoRecorder::SetNewVideoParams(double newaspect)
02027 {
02028     if (newaspect == video_aspect)
02029         return;
02030 
02031     video_aspect = newaspect;
02032 
02033     struct rtframeheader frameheader;
02034     memset(&frameheader, 0, sizeof(frameheader));
02035 
02036     frameheader.frametype = 'S';
02037     frameheader.comptype = 'M';
02038     frameheader.packetlength = sizeof(struct rtfileheader);
02039 
02040     WriteFrameheader(&frameheader);
02041 
02042     WriteFileHeader();
02043 }
02044 
02045 void NuppelVideoRecorder::WriteFileHeader(void)
02046 {
02047     struct rtfileheader fileheader;
02048     static const char finfo[12] = "MythTVVideo";
02049     static const char vers[5]   = "0.07";
02050 
02051     memset(&fileheader, 0, sizeof(fileheader));
02052     memcpy(fileheader.finfo, finfo, sizeof(fileheader.finfo));
02053     memcpy(fileheader.version, vers, sizeof(fileheader.version));
02054     fileheader.width  = w_out;
02055     fileheader.height = (int)(h_out * height_multiplier);
02056     fileheader.desiredwidth  = 0;
02057     fileheader.desiredheight = 0;
02058     fileheader.pimode = 'P';
02059     fileheader.aspect = video_aspect;
02060     fileheader.fps = video_frame_rate;
02061     fileheader.fps *= framerate_multiplier;
02062     fileheader.videoblocks = -1;
02063     fileheader.audioblocks = -1;
02064     fileheader.textsblocks = -1; // TODO: make only -1 if VBI support active?
02065     fileheader.keyframedist = KEYFRAMEDIST;
02066 
02067 #if HAVE_BIGENDIAN
02068     fileheader.width         = bswap_32(fileheader.width);
02069     fileheader.height        = bswap_32(fileheader.height);
02070     fileheader.desiredwidth  = bswap_32(fileheader.desiredwidth);
02071     fileheader.desiredheight = bswap_32(fileheader.desiredheight);
02072     fileheader.aspect        = bswap_dbl(fileheader.aspect);
02073     fileheader.fps           = bswap_dbl(fileheader.fps);
02074     fileheader.videoblocks   = bswap_32(fileheader.videoblocks);
02075     fileheader.audioblocks   = bswap_32(fileheader.audioblocks);
02076     fileheader.textsblocks   = bswap_32(fileheader.textsblocks);
02077     fileheader.keyframedist  = bswap_32(fileheader.keyframedist);
02078 #endif
02079     ringBuffer->Write(&fileheader, FILEHEADERSIZE);
02080 }
02081 
02082 void NuppelVideoRecorder::WriteHeader(void)
02083 {
02084     struct rtframeheader frameheader;
02085     static unsigned long int tbls[128];
02086 
02087     if (!videoFilters)
02088         InitFilters();
02089 
02090     WriteFileHeader();
02091 
02092     memset(&frameheader, 0, sizeof(frameheader));
02093     frameheader.frametype = 'D'; // compressor data
02094 
02095     if (useavcodec)
02096     {
02097         frameheader.comptype = 'F';
02098         frameheader.packetlength = mpa_vidctx->extradata_size;
02099 
02100         WriteFrameheader(&frameheader);
02101         ringBuffer->Write(mpa_vidctx->extradata, frameheader.packetlength);
02102     }
02103     else
02104     {
02105         frameheader.comptype = 'R'; // compressor data for RTjpeg
02106         frameheader.packetlength = sizeof(tbls);
02107 
02108         // compression configuration header
02109         WriteFrameheader(&frameheader);
02110 
02111         memset(tbls, 0, sizeof(tbls));
02112         ringBuffer->Write(tbls, sizeof(tbls));
02113     }
02114 
02115     memset(&frameheader, 0, sizeof(frameheader));
02116     frameheader.frametype = 'X'; // extended data
02117     frameheader.packetlength = sizeof(extendeddata);
02118 
02119     // extended data header
02120     WriteFrameheader(&frameheader);
02121 
02122     struct extendeddata moredata;
02123     memset(&moredata, 0, sizeof(extendeddata));
02124 
02125     moredata.version = 1;
02126     if (useavcodec)
02127     {
02128         int vidfcc = 0;
02129         switch(mpa_vidcodec->id)
02130         {
02131             case CODEC_ID_MPEG4:      vidfcc = FOURCC_DIVX; break;
02132             case CODEC_ID_WMV1:       vidfcc = FOURCC_WMV1; break;
02133             case CODEC_ID_MSMPEG4V3:  vidfcc = FOURCC_DIV3; break;
02134             case CODEC_ID_MSMPEG4V2:  vidfcc = FOURCC_MP42; break;
02135             case CODEC_ID_MSMPEG4V1:  vidfcc = FOURCC_MPG4; break;
02136             case CODEC_ID_MJPEG:      vidfcc = FOURCC_MJPG; break;
02137             case CODEC_ID_H263:       vidfcc = FOURCC_H263; break;
02138             case CODEC_ID_H263P:      vidfcc = FOURCC_H263; break;
02139             case CODEC_ID_H263I:      vidfcc = FOURCC_I263; break;
02140             case CODEC_ID_MPEG1VIDEO: vidfcc = FOURCC_MPEG; break;
02141             case CODEC_ID_MPEG2VIDEO: vidfcc = FOURCC_MPG2; break;
02142             case CODEC_ID_HUFFYUV:    vidfcc = FOURCC_HFYU; break;
02143             default: break;
02144         }
02145         moredata.video_fourcc = vidfcc;
02146         moredata.lavc_bitrate = mpa_vidctx->bit_rate;
02147         moredata.lavc_qmin = mpa_vidctx->qmin;
02148         moredata.lavc_qmax = mpa_vidctx->qmax;
02149         moredata.lavc_maxqdiff = mpa_vidctx->max_qdiff;
02150     }
02151     else
02152     {
02153         moredata.video_fourcc = FOURCC_RJPG;
02154         moredata.rtjpeg_quality = Q;
02155         moredata.rtjpeg_luma_filter = M1;
02156         moredata.rtjpeg_chroma_filter = M2;
02157     }
02158 
02159     if (compressaudio)
02160     {
02161         moredata.audio_fourcc = FOURCC_LAME;
02162         moredata.audio_compression_ratio = 11;
02163         moredata.audio_quality = mp3quality;
02164     }
02165     else
02166     {
02167         moredata.audio_fourcc = FOURCC_RAWA;
02168     }
02169 
02170     moredata.audio_sample_rate = audio_samplerate;
02171     moredata.audio_channels = audio_channels;
02172     moredata.audio_bits_per_sample = audio_bits;
02173 
02174     extendeddataOffset = ringBuffer->GetWritePosition();
02175 
02176 #if HAVE_BIGENDIAN
02177     moredata.version                 = bswap_32(moredata.version);
02178     moredata.video_fourcc            = bswap_32(moredata.video_fourcc);
02179     moredata.audio_fourcc            = bswap_32(moredata.audio_fourcc);
02180     moredata.audio_sample_rate       = bswap_32(moredata.audio_sample_rate);
02181     moredata.audio_bits_per_sample   = bswap_32(moredata.audio_bits_per_sample);
02182     moredata.audio_channels          = bswap_32(moredata.audio_channels);
02183     moredata.audio_compression_ratio = bswap_32(moredata.audio_compression_ratio);
02184     moredata.audio_quality           = bswap_32(moredata.audio_quality);
02185     moredata.rtjpeg_quality          = bswap_32(moredata.rtjpeg_quality);
02186     moredata.rtjpeg_luma_filter      = bswap_32(moredata.rtjpeg_luma_filter);
02187     moredata.rtjpeg_chroma_filter    = bswap_32(moredata.rtjpeg_chroma_filter);
02188     moredata.lavc_bitrate            = bswap_32(moredata.lavc_bitrate);
02189     moredata.lavc_qmin               = bswap_32(moredata.lavc_qmin);
02190     moredata.lavc_qmax               = bswap_32(moredata.lavc_qmax);
02191     moredata.lavc_maxqdiff           = bswap_32(moredata.lavc_maxqdiff);
02192     moredata.seektable_offset        = bswap_64(moredata.seektable_offset);
02193     moredata.keyframeadjust_offset   = bswap_64(moredata.keyframeadjust_offset);
02194 #endif
02195     ringBuffer->Write(&moredata, sizeof(moredata));
02196 
02197     last_block = 0;
02198     lf = 0; // that resets framenumber so that seeking in the
02199             // continues parts works too
02200 }
02201 
02202 void NuppelVideoRecorder::WriteSeekTable(void)
02203 {
02204     int numentries = seektable->size();
02205 
02206     struct rtframeheader frameheader;
02207     memset(&frameheader, 0, sizeof(frameheader));
02208     frameheader.frametype = 'Q'; // SeekTable
02209     frameheader.packetlength = sizeof(struct seektable_entry) * numentries;
02210 
02211     long long currentpos = ringBuffer->GetWritePosition();
02212 
02213     ringBuffer->Write(&frameheader, sizeof(frameheader));
02214 
02215     char *seekbuf = new char[frameheader.packetlength];
02216     int offset = 0;
02217 
02218     vector<struct seektable_entry>::iterator i = seektable->begin();
02219     for (; i != seektable->end(); i++)
02220     {
02221         memcpy(seekbuf + offset, (const void *)&(*i),
02222                sizeof(struct seektable_entry));
02223         offset += sizeof(struct seektable_entry);
02224     }
02225 
02226     ringBuffer->Write(seekbuf, frameheader.packetlength);
02227 
02228     ringBuffer->WriterSeek(extendeddataOffset +
02229                            offsetof(struct extendeddata, seektable_offset),
02230                            SEEK_SET);
02231 
02232     ringBuffer->Write(&currentpos, sizeof(long long));
02233 
02234     ringBuffer->WriterSeek(0, SEEK_END);
02235 
02236     delete [] seekbuf;
02237 }
02238 
02239 void NuppelVideoRecorder::WriteKeyFrameAdjustTable(
02240     const vector<struct kfatable_entry> &kfa_table)
02241 {
02242     int numentries = kfa_table.size();
02243 
02244     struct rtframeheader frameheader;
02245     memset(&frameheader, 0, sizeof(frameheader));
02246     frameheader.frametype = 'K'; // KFA Table
02247     frameheader.packetlength = sizeof(struct kfatable_entry) * numentries;
02248 
02249     long long currentpos = ringBuffer->GetWritePosition();
02250 
02251     ringBuffer->Write(&frameheader, sizeof(frameheader));
02252 
02253     char *kfa_buf = new char[frameheader.packetlength];
02254     uint offset = 0;
02255 
02256     vector<struct kfatable_entry>::const_iterator it = kfa_table.begin();
02257     for (; it != kfa_table.end() ; ++it)
02258     {
02259         memcpy(kfa_buf + offset, &(*it),
02260                sizeof(struct kfatable_entry));
02261         offset += sizeof(struct kfatable_entry);
02262     }
02263 
02264     ringBuffer->Write(kfa_buf, frameheader.packetlength);
02265 
02266 
02267     ringBuffer->WriterSeek(extendeddataOffset +
02268                            offsetof(struct extendeddata, keyframeadjust_offset),
02269                            SEEK_SET);
02270 
02271     ringBuffer->Write(&currentpos, sizeof(long long));
02272 
02273     ringBuffer->WriterSeek(0, SEEK_END);
02274 
02275     delete [] kfa_buf;
02276 }
02277 
02278 void NuppelVideoRecorder::UpdateSeekTable(int frame_num, long offset)
02279 {
02280     long long position = ringBuffer->GetWritePosition() + offset;
02281     struct seektable_entry ste;
02282     ste.file_offset = position;
02283     ste.keyframe_number = frame_num;
02284     seektable->push_back(ste);
02285 
02286     positionMapLock.lock();
02287     if (!positionMap.contains(ste.keyframe_number))
02288     {
02289         positionMapDelta[ste.keyframe_number] = position;
02290         positionMap[ste.keyframe_number] = position;
02291         lastPositionMapPos = position;
02292     }
02293     positionMapLock.unlock();
02294 }
02295 
02296 int NuppelVideoRecorder::CreateNuppelFile(void)
02297 {
02298     framesWritten = 0;
02299 
02300     if (!ringBuffer)
02301     {
02302         LOG(VB_GENERAL, LOG_ERR, LOC +
02303             "No ringbuffer, recorder wasn't initialized.");
02304         return -1;
02305     }
02306 
02307     if (!ringBuffer->IsOpen())
02308     {
02309         LOG(VB_GENERAL, LOG_ERR, LOC + "Ringbuffer isn't open");
02310         return -1;
02311     }
02312 
02313     WriteHeader();
02314 
02315     return 0;
02316 }
02317 
02318 void NuppelVideoRecorder::Reset(void)
02319 {
02320     ResetForNewFile();
02321 
02322     for (int i = 0; i < video_buffer_count; i++)
02323     {
02324         vidbuffertype *vidbuf = videobuffer[i];
02325         vidbuf->sample = 0;
02326         vidbuf->timecode = 0;
02327         vidbuf->freeToEncode = 0;
02328         vidbuf->freeToBuffer = 1;
02329         vidbuf->forcekey = 0;
02330     }
02331 
02332     for (int i = 0; i < audio_buffer_count; i++)
02333     {
02334         audbuffertype *audbuf = audiobuffer[i];
02335         audbuf->sample = 0;
02336         audbuf->timecode = 0;
02337         audbuf->freeToEncode = 0;
02338         audbuf->freeToBuffer = 1;
02339     }
02340 
02341     for (int i = 0; i < text_buffer_count; i++)
02342     {
02343         txtbuffertype *txtbuf = textbuffer[i];
02344         txtbuf->freeToEncode = 0;
02345         txtbuf->freeToBuffer = 1;
02346     }
02347 
02348     act_video_encode = 0;
02349     act_video_buffer = 0;
02350     act_audio_encode = 0;
02351     act_audio_buffer = 0;
02352     act_audio_sample = 0;
02353     act_text_encode = 0;
02354     act_text_buffer = 0;
02355 
02356     audiobytes = 0;
02357     effectivedsp = 0;
02358 
02359     if (useavcodec)
02360         SetupAVCodecVideo();
02361 
02362     if (curRecording)
02363         curRecording->ClearPositionMap(MARK_KEYFRAME);
02364 }
02365 
02366 void NuppelVideoRecorder::doAudioThread(void)
02367 {
02368     if (!audio_device)
02369     {
02370         LOG(VB_GENERAL, LOG_ERR, LOC +
02371             QString("Invalid audio device (%1), exiting").arg(audiodevice));
02372         return;
02373     }
02374 
02375     if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
02376     {
02377         LOG(VB_GENERAL, LOG_ERR, LOC +
02378             QString("Failed to open audio device %1").arg(audiodevice));
02379         return;
02380     }
02381 
02382     if (!audio_device->Start())
02383     {
02384         LOG(VB_GENERAL, LOG_ERR, LOC +
02385             QString("Failed to start audio capture on %1").arg(audiodevice));
02386         return;
02387     }
02388 
02389     struct timeval anow;
02390     unsigned char *buffer = new unsigned char[audio_buffer_size];
02391     int act = 0, lastread = 0;
02392     audio_bytes_per_sample = audio_channels * audio_bits / 8;
02393 
02394     while (IsHelperRequested() && !IsErrored())
02395     {
02396         {
02397             QMutexLocker locker(&pauseLock);
02398             if (request_pause)
02399             {
02400                 if (!audiopaused)
02401                 {
02402                     audiopaused = true;
02403                     pauseWait.wakeAll();
02404                     if (IsPaused(true) && tvrec)
02405                         tvrec->RecorderPaused();
02406                 }
02407                 unpauseWait.wait(&pauseLock, 100);
02408                 continue;
02409             }
02410             
02411             if (!request_pause && audiopaused)
02412             {
02413                 audiopaused = false;
02414                 unpauseWait.wakeAll();
02415             }
02416         }
02417 
02418         if (!IsHelperRequested() || IsErrored())
02419             break;
02420 
02421         lastread = audio_device->GetSamples(buffer, audio_buffer_size);
02422         if (audio_buffer_size != lastread)
02423         {
02424             LOG(VB_GENERAL, LOG_ERR, LOC +
02425                 QString("Short read, %1 of %2 bytes from ")
02426                     .arg(lastread).arg(audio_buffer_size) + audiodevice);
02427         }
02428 
02429         /* record the current time */
02430         /* Don't assume that the sound device's record buffer is empty
02431            (like we used to.) Measure to see how much stuff is in there,
02432            and correct for it when calculating the timestamp */
02433         gettimeofday(&anow, &tzone);
02434         int bytes_read = max(audio_device->GetNumReadyBytes(), 0);
02435 
02436         act = act_audio_buffer;
02437 
02438         if (!audiobuffer[act]->freeToBuffer)
02439         {
02440             LOG(VB_GENERAL, LOG_ERR, LOC + "Ran out of free AUDIO buffers :-(");
02441             act_audio_sample++;
02442             continue;
02443         }
02444 
02445         audiobuffer[act]->sample = act_audio_sample;
02446 
02447         /* calculate timecode. First compute the difference
02448            between now and stm (start time) */
02449         audiobuffer[act]->timecode = (anow.tv_sec - stm.tv_sec) * 1000 +
02450                                      anow.tv_usec / 1000 - stm.tv_usec / 1000;
02451         /* We want the timestamp to point to the start of this
02452            audio chunk. So, subtract off the length of the chunk
02453            and the length of audio still in the capture buffer. */
02454         audiobuffer[act]->timecode -= (int)(
02455                 (bytes_read + audio_buffer_size)
02456                  * 1000.0 / (audio_samplerate * audio_bytes_per_sample));
02457 
02458         memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size);
02459 
02460         audiobuffer[act]->freeToBuffer = 0;
02461         act_audio_buffer++;
02462         if (act_audio_buffer >= audio_buffer_count)
02463             act_audio_buffer = 0;
02464         audiobuffer[act]->freeToEncode = 1;
02465 
02466         act_audio_sample++;
02467     }
02468 
02469     delete [] buffer;
02470 
02471     if (audio_device->IsOpen())
02472         audio_device->Close();
02473 }
02474 
02475 #ifdef USING_V4L2
02476 void NuppelVideoRecorder::FormatTT(struct VBIData *vbidata)
02477 {
02478     struct timeval tnow;
02479     gettimeofday(&tnow, &tzone);
02480 
02481     int act = act_text_buffer;
02482     if (!textbuffer[act]->freeToBuffer)
02483     {
02484         LOG(VB_GENERAL, LOG_ERR, LOC +
02485             QString("Teletext #%1: ran out of free TEXT buffers :-(").arg(act));
02486         return;
02487     }
02488 
02489     // calculate timecode:
02490     // compute the difference  between now and stm (start time)
02491     textbuffer[act]->timecode = (tnow.tv_sec-stm.tv_sec) * 1000 +
02492                                 tnow.tv_usec/1000 - stm.tv_usec/1000;
02493     textbuffer[act]->pagenr = (vbidata->teletextpage.pgno << 16) +
02494                               vbidata->teletextpage.subno;
02495 
02496     unsigned char *inpos = vbidata->teletextpage.data[0];
02497     unsigned char *outpos = textbuffer[act]->buffer;
02498     *outpos = 0;
02499     struct teletextsubtitle st = { 0 };
02500     unsigned char linebuf[VT_WIDTH + 1];
02501     unsigned char *linebufpos = linebuf;
02502 
02503     for (int y = 0; y < VT_HEIGHT; y++)
02504     {
02505         char c = ' ';
02506         char last_c = ' ';
02507         int hid = 0;
02508         int gfx = 0;
02509         int dbl = 0;
02510         int box = 0;
02511         int sep = 0;
02512         int hold = 0;
02513         int visible = 0;
02514         int fg = 7;
02515         int bg = 0;
02516 
02517         for (int x = 0; x < VT_WIDTH; ++x)
02518         {
02519             c = *inpos++;
02520             switch (c)
02521             {
02522                 case 0x00 ... 0x07:     /* alpha + fg color */
02523                     fg = c & 7;
02524                     gfx = 0;
02525                     sep = 0;
02526                     hid = 0;
02527                     goto ctrl;
02528                 case 0x08:              /* flash */
02529                     goto ctrl;
02530                 case 0x09:              /* steady */
02531                     goto ctrl;
02532                 case 0x0a:              /* end box */
02533                     box = 0;
02534                     goto ctrl;
02535                 case 0x0b:              /* start box */
02536                     box = 1;
02537                     goto ctrl;
02538                 case 0x0c:              /* normal height */
02539                     dbl = 0;
02540                     goto ctrl;
02541                 case 0x0d:              /* double height */
02542                     if (y < VT_HEIGHT-2)        /* ignored on last 2 lines */
02543                     {
02544                         dbl = 1;
02545                     }
02546                     goto ctrl;
02547                 case 0x10 ... 0x17:     /* gfx + fg color */
02548                     fg = c & 7;
02549                     gfx = 1;
02550                     hid = 0;
02551                     goto ctrl;
02552                 case 0x18:              /* conceal */
02553                     hid = 1;
02554                     goto ctrl;
02555                 case 0x19:              /* contiguous gfx */
02556                     hid = 0;
02557                     sep = 0;
02558                     goto ctrl;
02559                 case 0x1a:              /* separate gfx */
02560                     sep = 1;
02561                     goto ctrl;
02562                 case 0x1c:              /* black bf */
02563                     bg = 0;
02564                     goto ctrl;
02565                 case 0x1d:              /* new bg */
02566                     bg = fg;
02567                     goto ctrl;
02568                 case 0x1e:              /* hold gfx */
02569                     hold = 1;
02570                     goto ctrl;
02571                 case 0x1f:              /* release gfx */
02572                     hold = 0;
02573                     goto ctrl;
02574                 case 0x0e:              /* SO */
02575                     goto ctrl;
02576                 case 0x0f:              /* SI */
02577                     goto ctrl;
02578                 case 0x1b:              /* ESC */
02579                     goto ctrl;
02580 
02581                 ctrl:
02582                     c = ' ';
02583                     if (hold && gfx)
02584                         c = last_c;
02585                     break;
02586             }
02587             if (gfx)
02588                 if ((c & 0xa0) == 0x20)
02589                 {
02590                     last_c = c;
02591                     c += (c & 0x40) ? 32 : -32;
02592                 }
02593             if (hid)
02594                 c = ' ';
02595 
02596             if (visible || (c != ' '))
02597             {
02598                 if (!visible)
02599                 {
02600                     st.row = y;
02601                     st.col = x;
02602                     st.dbl = dbl;
02603                     st.fg  = fg;
02604                     st.bg  = bg;
02605                     linebufpos = linebuf;
02606                     *linebufpos = 0;
02607                 }
02608                 *linebufpos++ = c;
02609                 *linebufpos = 0;
02610                 visible = 1;
02611             }
02612         }
02613         if (visible)
02614         {
02615             st.len = linebufpos - linebuf + 1;;
02616             int max = 200;
02617             int bufsize = ((outpos - textbuffer[act]->buffer + 1) + st.len);
02618             if (bufsize > max)
02619                 break;
02620             memcpy(outpos, &st, sizeof(st));
02621             outpos += sizeof(st);
02622             if (st.len < 42)
02623             {
02624                 memcpy(outpos, linebuf, st.len);
02625                 outpos += st.len;
02626             }
02627             else
02628             {
02629                 memcpy(outpos, linebuf, 41);
02630                 outpos += 41;
02631             }
02632             *outpos = 0;
02633         }
02634     }
02635 
02636     textbuffer[act]->bufferlen = outpos - textbuffer[act]->buffer + 1;
02637     textbuffer[act]->freeToBuffer = 0;
02638     act_text_buffer++;
02639     if (act_text_buffer >= text_buffer_count)
02640         act_text_buffer = 0;
02641     textbuffer[act]->freeToEncode = 1;
02642 }
02643 #else  // USING_V4L2
02644 void NuppelVideoRecorder::FormatTT(struct VBIData*) {}
02645 #endif // USING_V4L2
02646 
02647 void NuppelVideoRecorder::FormatCC(uint code1, uint code2)
02648 {
02649     struct timeval tnow;
02650     gettimeofday (&tnow, &tzone);
02651 
02652     // calculate timecode:
02653     // compute the difference  between now and stm (start time)
02654     int tc = (tnow.tv_sec - stm.tv_sec) * 1000 +
02655              tnow.tv_usec / 1000 - stm.tv_usec / 1000;
02656 
02657     ccd->FormatCC(tc, code1, code2);
02658 }
02659 
02660 void NuppelVideoRecorder::AddTextData(unsigned char *buf, int len,
02661                                       int64_t timecode, char /*type*/)
02662 {
02663     int act = act_text_buffer;
02664     if (!textbuffer[act]->freeToBuffer)
02665     {
02666         LOG(VB_GENERAL, LOG_ERR, LOC + QString("Teletext#%1").arg(act) +
02667                 " ran out of free TEXT buffers :-(");
02668         return;
02669     }
02670 
02671     textbuffer[act]->timecode = timecode;
02672     memcpy(textbuffer[act]->buffer, buf, len);
02673     textbuffer[act]->bufferlen = len + sizeof(ccsubtitle);
02674 
02675     textbuffer[act]->freeToBuffer = 0;
02676     act_text_buffer++;
02677     if (act_text_buffer >= text_buffer_count)
02678         act_text_buffer = 0;
02679     textbuffer[act]->freeToEncode = 1;
02680 }
02681 
02682 void NuppelVideoRecorder::doWriteThread(void)
02683 {
02684     while (IsHelperRequested() && !IsErrored())
02685     {
02686         {
02687             QMutexLocker locker(&pauseLock);
02688             if (request_pause)
02689             {
02690                 if (!writepaused)
02691                 {
02692                     writepaused = true;
02693                     pauseWait.wakeAll();
02694                     if (IsPaused(true) && tvrec)
02695                         tvrec->RecorderPaused();
02696                 }
02697                 unpauseWait.wait(&pauseLock, 100);
02698                 continue;
02699             }
02700             
02701             if (!request_pause && writepaused)
02702             {
02703                 writepaused = false;
02704                 unpauseWait.wakeAll();
02705             }
02706         }
02707 
02708         if (!IsHelperRequested() || IsErrored())
02709             break;
02710 
02711         CheckForRingBufferSwitch();
02712 
02713         enum
02714         { ACTION_NONE,
02715           ACTION_VIDEO,
02716           ACTION_AUDIO,
02717           ACTION_TEXT
02718         } action = ACTION_NONE;
02719         int firsttimecode = -1;
02720 
02721         if (videobuffer[act_video_encode]->freeToEncode)
02722         {
02723             action = ACTION_VIDEO;
02724             firsttimecode = videobuffer[act_video_encode]->timecode;
02725         }
02726 
02727         if (audio_buffer_count &&
02728             audiobuffer[act_audio_encode]->freeToEncode &&
02729             (action == ACTION_NONE ||
02730              (audiobuffer[act_audio_encode]->timecode < firsttimecode)))
02731         {
02732             action = ACTION_AUDIO;
02733             firsttimecode = audiobuffer[act_audio_encode]->timecode;
02734         }
02735 
02736         if (text_buffer_count &&
02737             textbuffer[act_text_encode]->freeToEncode &&
02738             (action == ACTION_NONE ||
02739              (textbuffer[act_text_encode]->timecode < firsttimecode)))
02740         {
02741             action = ACTION_TEXT;
02742         }
02743 
02744         switch (action)
02745         {
02746             case ACTION_VIDEO:
02747             {
02748                 VideoFrame frame;
02749                 init(&frame,
02750                      FMT_YV12, videobuffer[act_video_encode]->buffer,
02751                      width, height, videobuffer[act_video_encode]->bufferlen);
02752 
02753                 frame.frameNumber = videobuffer[act_video_encode]->sample;
02754                 frame.timecode = videobuffer[act_video_encode]->timecode;
02755                 frame.forcekey = videobuffer[act_video_encode]->forcekey;
02756 
02757                 WriteVideo(&frame);
02758 
02759                 videobuffer[act_video_encode]->sample = 0;
02760                 videobuffer[act_video_encode]->freeToEncode = 0;
02761                 videobuffer[act_video_encode]->freeToBuffer = 1;
02762                 videobuffer[act_video_encode]->forcekey = 0;
02763                 act_video_encode++;
02764                 if (act_video_encode >= video_buffer_count)
02765                     act_video_encode = 0;
02766                 break;
02767             }
02768             case ACTION_AUDIO:
02769             {
02770                 WriteAudio(audiobuffer[act_audio_encode]->buffer,
02771                            audiobuffer[act_audio_encode]->sample,
02772                            audiobuffer[act_audio_encode]->timecode);
02773                 if (IsErrored()) {
02774                     LOG(VB_GENERAL, LOG_ERR, LOC +
02775                         "ACTION_AUDIO cannot be completed due to error.");
02776                     StopRecording();
02777                     break;
02778                 }
02779                 audiobuffer[act_audio_encode]->sample = 0;
02780                 audiobuffer[act_audio_encode]->freeToEncode = 0;
02781                 audiobuffer[act_audio_encode]->freeToBuffer = 1;
02782                 act_audio_encode++;
02783                 if (act_audio_encode >= audio_buffer_count)
02784                     act_audio_encode = 0;
02785                 break;
02786             }
02787             case ACTION_TEXT:
02788             {
02789                 WriteText(textbuffer[act_text_encode]->buffer,
02790                           textbuffer[act_text_encode]->bufferlen,
02791                           textbuffer[act_text_encode]->timecode,
02792                           textbuffer[act_text_encode]->pagenr);
02793                 textbuffer[act_text_encode]->freeToEncode = 0;
02794                 textbuffer[act_text_encode]->freeToBuffer = 1;
02795                 act_text_encode++;
02796                 if (act_text_encode >= text_buffer_count)
02797                     act_text_encode = 0;
02798                 break;
02799             }
02800             default:
02801             {
02802                 usleep(100);
02803                 break;
02804             }
02805         }
02806     }
02807 }
02808 
02809 void NuppelVideoRecorder::SetNextRecording(const ProgramInfo *progInf,
02810                                            RingBuffer *rb)
02811 {
02812     // First we do some of the time consuming stuff we can do now
02813     SavePositionMap(true);
02814     ringBuffer->WriterFlush();
02815     if (curRecording)
02816         curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
02817 
02818     // Then we set the next info
02819     QMutexLocker locker(&nextRingBufferLock);
02820     nextRecording = NULL;
02821     if (progInf)
02822         nextRecording = new ProgramInfo(*progInf);
02823     nextRingBuffer = rb;
02824 }
02825 
02826 void NuppelVideoRecorder::ResetForNewFile(void)
02827 {
02828     framesWritten = 0;
02829     lf = 0;
02830     last_block = 0;
02831 
02832     seektable->clear();
02833 
02834     ClearStatistics();
02835 
02836     positionMapLock.lock();
02837     positionMap.clear();
02838     positionMapDelta.clear();
02839     positionMapLock.unlock();
02840 
02841     if (go7007)
02842         resetcapture = true;
02843 }
02844 
02845 void NuppelVideoRecorder::StartNewFile(void)
02846 {
02847     CreateNuppelFile();
02848 }
02849 
02850 void NuppelVideoRecorder::FinishRecording(void)
02851 {
02852     ringBuffer->WriterFlush();
02853 
02854     WriteSeekTable();
02855 
02856     if (curRecording)
02857     {
02858         curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
02859         SavePositionMap(true);
02860     }
02861     positionMapLock.lock();
02862     positionMap.clear();
02863     positionMapDelta.clear();
02864     positionMapLock.unlock();
02865 }
02866 
02867 void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
02868                                      bool forcekey)
02869 {
02870     int tmp = 0;
02871     lzo_uint out_len = OUT_LEN;
02872     struct rtframeheader frameheader;
02873     int raw = 0, compressthis = compression;
02874     uint8_t *planes[3];
02875     int len = frame->size;
02876     int fnum = frame->frameNumber;
02877     long long timecode = frame->timecode;
02878     unsigned char *buf = frame->buf;
02879 
02880     memset(&frameheader, 0, sizeof(frameheader));
02881 
02882     planes[0] = buf;
02883     planes[1] = planes[0] + frame->width * frame->height;
02884     planes[2] = planes[1] + (frame->width * frame->height) /
02885                             (picture_format == PIX_FMT_YUV422P ? 2 : 4);
02886 
02887     if (lf == 0)
02888     {   // this will be triggered every new file
02889         lf = fnum;
02890         startnum = fnum;
02891         lasttimecode = 0;
02892         frameofgop = 0;
02893         forcekey = true;
02894     }
02895 
02896     // see if it's time for a seeker header, sync information and a keyframe
02897     frameheader.keyframe  = frameofgop;             // no keyframe defaulted
02898 
02899     bool wantkeyframe = forcekey;
02900 
02901     bool writesync = false;
02902 
02903     if (!go7007 && (((fnum-startnum)>>1) % keyframedist == 0 && !skipsync))
02904         writesync = true;
02905     else if (go7007 && frame->forcekey)
02906         writesync = true;
02907 
02908     if (writesync)
02909     {
02910         ringBuffer->Write("RTjjjjjjjjjjjjjjjjjjjjjjjj", FRAMEHEADERSIZE);
02911 
02912         UpdateSeekTable(((fnum - startnum) >> 1) / keyframedist);
02913 
02914         frameheader.frametype    = 'S';           // sync frame
02915         frameheader.comptype     = 'V';           // video sync information
02916         frameheader.filters      = 0;             // no filters applied
02917         frameheader.packetlength = 0;             // no data packet
02918         frameheader.timecode     = (fnum-startnum)>>1;
02919         // write video sync info
02920         WriteFrameheader(&frameheader);
02921         frameheader.frametype    = 'S';           // sync frame
02922         frameheader.comptype     = 'A';           // video sync information
02923         frameheader.filters      = 0;             // no filters applied
02924         frameheader.packetlength = 0;             // no data packet
02925         frameheader.timecode     = effectivedsp;  // effective dsp frequency
02926         // write audio sync info
02927         WriteFrameheader(&frameheader);
02928 
02929         wantkeyframe = true;
02930         //ringBuffer->Sync();
02931     }
02932 
02933     if (wantkeyframe)
02934     {
02935         frameheader.keyframe=0;
02936         frameofgop=0;
02937     }
02938 
02939     if (videoFilters)
02940         videoFilters->ProcessFrame(frame);
02941 
02942     if (useavcodec)
02943     {
02944         mpa_picture.data[0] = planes[0];
02945         mpa_picture.data[1] = planes[1];
02946         mpa_picture.data[2] = planes[2];
02947         mpa_picture.linesize[0] = frame->width;
02948         mpa_picture.linesize[1] = frame->width / 2;
02949         mpa_picture.linesize[2] = frame->width / 2;
02950         mpa_picture.type = FF_BUFFER_TYPE_SHARED;
02951 
02952         if (wantkeyframe)
02953             mpa_picture.pict_type = AV_PICTURE_TYPE_I;
02954         else
02955             mpa_picture.pict_type = AV_PICTURE_TYPE_NONE;
02956 
02957         if (!hardware_encode)
02958         {
02959             AVPacket packet;
02960             packet.data = (uint8_t *)strm;
02961             packet.size = len;
02962 
02963             int got_packet = 0;
02964 
02965             QMutexLocker locker(avcodeclock);
02966             tmp = avcodec_encode_video2(mpa_vidctx, &packet, &mpa_picture,
02967                                         &got_packet);
02968 
02969             if (tmp < 0 || !got_packet)
02970             {
02971                 LOG(VB_GENERAL, LOG_ERR, LOC +
02972                     "WriteVideo : avcodec_encode_video() failed");
02973                 return;
02974             }
02975         }
02976     }
02977     else
02978     {
02979         int freecount = 0;
02980         freecount = act_video_buffer > act_video_encode ?
02981                     video_buffer_count - (act_video_buffer - act_video_encode) :
02982                     act_video_encode - act_video_buffer;
02983 
02984         if (freecount < (video_buffer_count / 3))
02985             compressthis = 0; // speed up the encode process
02986 
02987         if (freecount < 5)
02988             raw = 1; // speed up the encode process
02989 
02990         if (transcoding)
02991         {
02992             raw = 0;
02993             compressthis = 1;
02994         }
02995 
02996         if (!raw)
02997         {
02998             if (wantkeyframe)
02999                 rtjc->SetNextKey();
03000             tmp = rtjc->Compress(strm, planes);
03001         }
03002         else
03003             tmp = len;
03004 
03005         // here is lzo compression afterwards
03006         if (compressthis)
03007         {
03008             int r = 0;
03009             if (raw)
03010                 r = lzo1x_1_compress((unsigned char*)buf, len,
03011                                      out, &out_len, wrkmem);
03012             else
03013                 r = lzo1x_1_compress((unsigned char *)strm, tmp, out,
03014                                      &out_len, wrkmem);
03015             if (r != LZO_E_OK)
03016             {
03017                 LOG(VB_GENERAL, LOG_ERR, LOC + "lzo compression failed");
03018                 return;
03019             }
03020         }
03021     }
03022 
03023     frameheader.frametype = 'V'; // video frame
03024     frameheader.timecode  = timecode;
03025     lasttimecode = frameheader.timecode;
03026     frameheader.filters   = 0;             // no filters applied
03027 
03028     // compr ends here
03029     if (useavcodec)
03030     {
03031         if (mpa_vidcodec->id == CODEC_ID_RAWVIDEO)
03032         {
03033             frameheader.comptype = '0';
03034             frameheader.packetlength = len;
03035             WriteFrameheader(&frameheader);
03036             ringBuffer->Write(buf, len);
03037         }
03038         else if (hardware_encode)
03039         {
03040             frameheader.comptype = '4';
03041             frameheader.packetlength = len;
03042             WriteFrameheader(&frameheader);
03043             ringBuffer->Write(buf, len);
03044         }
03045         else
03046         {
03047             frameheader.comptype = '4';
03048             frameheader.packetlength = tmp;
03049             WriteFrameheader(&frameheader);
03050             ringBuffer->Write(strm, tmp);
03051         }
03052     }
03053     else if (compressthis == 0 || (tmp < (int)out_len))
03054     {
03055         if (!raw)
03056         {
03057             frameheader.comptype  = '1'; // video compression: RTjpeg only
03058             frameheader.packetlength = tmp;
03059             WriteFrameheader(&frameheader);
03060             ringBuffer->Write(strm, tmp);
03061         }
03062         else
03063         {
03064             frameheader.comptype  = '0'; // raw YUV420
03065             frameheader.packetlength = len;
03066             WriteFrameheader(&frameheader);
03067             ringBuffer->Write(buf, len); // we write buf directly
03068         }
03069     }
03070     else
03071     {
03072         if (!raw)
03073             frameheader.comptype  = '2'; // video compression: RTjpeg with lzo
03074         else
03075             frameheader.comptype  = '3'; // raw YUV420 with lzo
03076         frameheader.packetlength = out_len;
03077         WriteFrameheader(&frameheader);
03078         ringBuffer->Write(out, out_len);
03079     }
03080 
03081     frameofgop++;
03082     framesWritten++;
03083 
03084     // now we reset the last frame number so that we can find out
03085     // how many frames we didn't get next time
03086     lf = fnum;
03087 }
03088 
03089 #if HAVE_BIGENDIAN
03090 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
03091     __attribute__ ((unused)); /* <- suppress compiler warning */
03092 
03093 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
03094 {
03095     for (int i = 0; i < audio_channels * buf_cnt; i++)
03096         buf[i] = bswap_16(buf[i]);
03097 }
03098 #endif
03099 
03100 void NuppelVideoRecorder::WriteAudio(unsigned char *buf, int fnum, int timecode)
03101 {
03102     struct rtframeheader frameheader;
03103     double mt;
03104     double eff;
03105     double abytes;
03106 
03107     if (last_block == 0)
03108     {
03109         firsttc = -1;
03110     }
03111 
03112     if (last_block != 0)
03113     {
03114         if (fnum != (last_block+1))
03115         {
03116             audio_behind = fnum - (last_block+1);
03117             LOG(VB_RECORD, LOG_INFO, LOC + QString("audio behind %1 %2").
03118                     arg(last_block).arg(fnum));
03119         }
03120     }
03121 
03122     frameheader.frametype = 'A'; // audio frame
03123     frameheader.timecode = timecode;
03124 
03125     if (firsttc == -1)
03126     {
03127         firsttc = timecode;
03128 #if 0
03129         LOG(VB_GENERAL, LOG_DEBUG, LOC +
03130             QString("first timecode=%1").arg(firsttc));
03131 #endif
03132     }
03133     else
03134     {
03135         timecode -= firsttc; // this is to avoid the lack between the beginning
03136                              // of recording and the first timestamp, maybe we
03137                              // can calculate the audio-video +-lack at the
03138                             // beginning too
03139         abytes = (double)audiobytes; // - (double)audio_buffer_size;
03140                                      // wrong guess ;-)
03141         // need seconds instead of msec's
03142         mt = (double)timecode;
03143         if (mt > 0.0)
03144         {
03145             eff = (abytes / mt) * (100000.0 / audio_bytes_per_sample);
03146             effectivedsp = (int)eff;
03147         }
03148     }
03149 
03150     if (compressaudio)
03151     {
03152         char mp3gapless[7200];
03153         int compressedsize = 0;
03154         int gaplesssize = 0;
03155         int lameret = 0;
03156 
03157         int sample_cnt = audio_buffer_size / audio_bytes_per_sample;
03158 
03159 #if HAVE_BIGENDIAN
03160         bswap_16_buf((short int*) buf, sample_cnt, audio_channels);
03161 #endif
03162 
03163         if (audio_channels == 2)
03164         {
03165             lameret = lame_encode_buffer_interleaved(
03166                 gf, (short int*) buf, sample_cnt,
03167                 (unsigned char*) mp3buf, mp3buf_size);
03168         }
03169         else
03170         {
03171             lameret = lame_encode_buffer(
03172                 gf, (short int*) buf, (short int*) buf, sample_cnt,
03173                 (unsigned char*) mp3buf, mp3buf_size);
03174         }
03175 
03176         if (lameret < 0)
03177         {
03178             LOG(VB_GENERAL, LOG_ERR, LOC +
03179                 QString("lame error '%1'").arg(lameret));
03180             _error = QString("Audio Encoding Error '%1'")
03181                 .arg(lameret);
03182             return;
03183         }
03184         compressedsize = lameret;
03185 
03186         lameret = lame_encode_flush_nogap(gf, (unsigned char *)mp3gapless,
03187                                           7200);
03188         if (lameret < 0)
03189         {
03190             LOG(VB_GENERAL, LOG_ERR, LOC +
03191                 QString("lame error '%1'").arg(lameret));
03192             _error = QString("Audio Encoding Error '%1'")
03193                 .arg(lameret);
03194             return;
03195         }
03196         gaplesssize = lameret;
03197 
03198         frameheader.comptype = '3'; // audio is compressed
03199         frameheader.packetlength = compressedsize + gaplesssize;
03200 
03201         if (frameheader.packetlength > 0)
03202         {
03203             WriteFrameheader(&frameheader);
03204             ringBuffer->Write(mp3buf, compressedsize);
03205             ringBuffer->Write(mp3gapless, gaplesssize);
03206         }
03207         audiobytes += audio_buffer_size;
03208     }
03209     else
03210     {
03211         frameheader.comptype = '0'; // uncompressed audio
03212         frameheader.packetlength = audio_buffer_size;
03213 
03214         WriteFrameheader(&frameheader);
03215         ringBuffer->Write(buf, audio_buffer_size);
03216         audiobytes += audio_buffer_size; // only audio no header!!
03217     }
03218 
03219     // this will probably never happen and if there would be a
03220     // 'uncountable' video frame drop -> material==worthless
03221     if (audio_behind > 0)
03222     {
03223         LOG(VB_RECORD, LOG_INFO, LOC + "audio behind");
03224         frameheader.frametype = 'A'; // audio frame
03225         frameheader.comptype  = 'N'; // output a nullframe with
03226         frameheader.packetlength = 0;
03227         WriteFrameheader(&frameheader);
03228         audiobytes += audio_buffer_size;
03229         audio_behind--;
03230     }
03231 
03232     last_block = fnum;
03233 }
03234 
03235 void NuppelVideoRecorder::WriteText(unsigned char *buf, int len, int timecode,
03236                                     int pagenr)
03237 {
03238     struct rtframeheader frameheader;
03239 
03240     frameheader.frametype = 'T'; // text frame
03241     frameheader.timecode = timecode;
03242 
03243     if (VBIMode::PAL_TT == vbimode)
03244     {
03245         frameheader.comptype = 'T'; // european teletext
03246         frameheader.packetlength = len + 4;
03247         WriteFrameheader(&frameheader);
03248         union page_t {
03249             int32_t val32;
03250             struct { int8_t a,b,c,d; } val8;
03251         } v;
03252         v.val32 = pagenr;
03253         ringBuffer->Write(&v.val8.d, sizeof(int8_t));
03254         ringBuffer->Write(&v.val8.c, sizeof(int8_t));
03255         ringBuffer->Write(&v.val8.b, sizeof(int8_t));
03256         ringBuffer->Write(&v.val8.a, sizeof(int8_t));
03257         ringBuffer->Write(buf, len);
03258     }
03259     else if (VBIMode::NTSC_CC == vbimode)
03260     {
03261         frameheader.comptype = 'C'; // NTSC CC
03262         frameheader.packetlength = len;
03263 
03264         WriteFrameheader(&frameheader);
03265         ringBuffer->Write(buf, len);
03266     }
03267 }
03268 
03269 /* vim: set expandtab tabstop=4 shiftwidth=4: */
03270 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends