Ticket #6888: live_transcode.2.patch

File live_transcode.2.patch, 36.6 KB (added by buehlmann@…, 3 years ago)
  • libs/libmythtv/dvbrecorder.cpp

     
    156156    SetOption("videodevice", videodev); 
    157157    DTVRecorder::SetOption("tvformat", gContext->GetSetting("TVFormat")); 
    158158    SetStrOption(profile,  "recordingtype"); 
     159    SetIntOption(profile, "transcode"); 
     160    SetStrOption(profile, "videocodec"); 
     161    SetIntOption(profile, "videobitrate"); 
     162    SetStrOption(profile, "audiocodec"); 
     163    SetIntOption(profile, "audiobitrate"); 
    159164} 
    160165 
    161166void DVBRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) 
     
    562567    if (!_payload_buffer.empty()) 
    563568    { 
    564569        if (ringBuffer) 
    565             ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     570            if (doTranscode) 
     571            { 
     572                transcoder->ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     573            } 
     574            else 
     575            { 
     576                ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     577            } 
    566578        _payload_buffer.clear(); 
    567579    } 
    568580 
    569581    if (ringBuffer) 
    570         ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 
     582        if (doTranscode) 
     583        { 
     584            transcoder->ringBuffer->Write((unsigned char*)tspacket.data(), TSPacket::SIZE); 
     585        } 
     586        else 
     587        { 
     588            ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 
     589        } 
    571590} 
  • libs/libmythtv/avformatdecoder.cpp

     
    11851185 
    11861186        if (stream->sample_aspect_ratio.num) 
    11871187            aspect_ratio = av_q2d(stream->sample_aspect_ratio); 
    1188         else if (enc->sample_aspect_ratio.num == 0) 
     1188        else if (enc->sample_aspect_ratio.num) 
    11891189            aspect_ratio = av_q2d(enc->sample_aspect_ratio); 
    11901190        else 
    11911191            aspect_ratio = 1.0f; 
  • libs/libmythtv/transcoder.h

     
     1// -*- Mode: c++ -*- 
     2/* 
     3 *  Copyright (C) Rene Buehlmann 2009 
     4 *   
     5 *  Copyright notice is in dvbrecorder.cpp of the MythTV project. 
     6 */ 
     7 
     8#ifndef TRANSCODER_H 
     9#define TRANSCODER_H 
     10 
     11// C++ includes 
     12//#include <vector> 
     13//#include <deque> 
     14using namespace std; 
     15 
     16// Qt includes 
     17//#include "dtvrecorder.h" 
     18//#include "tspacket.h" 
     19//#include "DeviceReadBuffer.h" 
     20 
     21#include "RingBuffer.h" 
     22#include "RealRingBuffer.h" 
     23 
     24class Transcoder: public QThread 
     25{ 
     26public: 
     27    Transcoder(RingBuffer *output, std::string a = "Transcoder"); 
     28    ~Transcoder(); 
     29    void setParam(const QString &name, const QString &value); 
     30    void setParam(const QString &name, int value); 
     31    int Write(unsigned char *buf, int len); 
     32    RealRingBuffer *ringBuffer; 
     33    virtual void run(); 
     34private: 
     35    std::string name; 
     36    RingBuffer *rb; 
     37    CodecID vcodec; 
     38    CodecID acodec; 
     39    int videobitrate; 
     40    int audiobitrate; 
     41    int width; 
     42    int height; 
     43    bool transcode_audio; 
     44    bool transcode_video; 
     45}; 
     46 
     47#endif 
     48 
  • libs/libmythtv/libmythtv.pro

     
    158158HEADERS += transporteditor.h        listingsources.h 
    159159HEADERS += myth_imgconvert.h 
    160160HEADERS += channelgroup.h           channelgroupsettings.h 
     161HEADERS += RealRingBuffer.h         transcoder.h 
    161162 
    162163# Remove when everything is switched to MythUI 
    163164HEADERS += proglist_qt.h 
     
    183184SOURCES += transporteditor.cpp 
    184185SOURCES += channelgroup.cpp         channelgroupsettings.cpp 
    185186SOURCES += myth_imgconvert.cpp 
     187SOURCES += RealRingBuffer.cpp       transcoder.cpp 
    186188 
    187189# Remove when everything is switched to MythUI 
    188190SOURCES += proglist_qt.cpp 
  • libs/libmythtv/dvbrecorder.h

     
    123123    unsigned char _continuity_counter[0x1fff + 1]; 
    124124    vector<TSPacket> _scratch; 
    125125 
     126    //Transcoding 
     127    Transcoder  *tc; 
     128 
    126129    // Statistics 
    127130    mutable uint  _continuity_error_count; 
    128131    mutable uint  _stream_overflow_count; 
  • libs/libmythtv/recorderbase.cpp

     
    3232      vbimode(0), ntsc(true), ntsc_framerate(true), video_frame_rate(29.97), 
    3333      m_videoAspect(0), m_videoHeight(0), m_videoWidth(0), curRecording(NULL), 
    3434      request_pause(false), paused(false), nextRingBuffer(NULL), nextRecording(NULL), 
    35       positionMapType(MARK_GOP_BYFRAME), positionMapLock() 
     35      positionMapType(MARK_GOP_BYFRAME), positionMapLock(), doTranscode(false) 
    3636{ 
    3737    QMutexLocker locker(&avcodeclock); 
    3838    avcodec_init(); // init CRC's 
     
    4040 
    4141RecorderBase::~RecorderBase(void) 
    4242{ 
     43    if (doTranscode) 
     44    { 
     45        VERBOSE(VB_RECORD,  LOC + "Waiting for transcoder to finish..."); 
     46        transcoder->wait(); 
     47        VERBOSE(VB_RECORD,  LOC + "Transcoder finished!"); 
     48        delete transcoder; 
     49        transcoder = NULL; 
     50    } 
    4351    if (weMadeBuffer && ringBuffer) 
    4452    { 
    4553        delete ringBuffer; 
     
    6169            msg = " '" + rbuf->GetFilename() + "'"; 
    6270        VERBOSE(VB_RECORD,  LOC + "SetRingBuffer("<<rbuf<<")"<<msg); 
    6371    } 
     72    if (doTranscode) 
     73    { 
     74        VERBOSE(VB_RECORD,  LOC + "Start transcoder"); 
     75        transcoder = new Transcoder(rbuf, "TC"); 
     76        transcoder->setParam("videocodec", videocodec); 
     77        transcoder->setParam("audiocodec", audiocodec); 
     78        transcoder->setParam("videobitrate", videobitrate); 
     79        transcoder->setParam("audiobitrate", audiobitrate); 
     80        transcoder->start(); 
     81    } 
    6482    ringBuffer = rbuf; 
    6583    weMadeBuffer = false; 
    6684} 
     
    87105{ 
    88106    if (name == "videocodec") 
    89107        videocodec = value; 
     108    else if (name == "audiocodec") 
     109        audiocodec = value; 
    90110    else if (name == "audiodevice") 
    91111        audiodevice = value; 
    92112    else if (name == "videodevice") 
     
    131151 
    132152void RecorderBase::SetOption(const QString &name, int value) 
    133153{ 
    134     VERBOSE(VB_IMPORTANT, LOC_ERR + 
     154    if (name == "videobitrate") 
     155        videobitrate = value; 
     156    else if (name == "audiobitrate") 
     157        audiobitrate = value; 
     158    else if (name == "transcode") 
     159        doTranscode = value; 
     160    else 
     161        VERBOSE(VB_IMPORTANT, LOC_ERR + 
    135162            QString("SetOption(): Unknown int option: %1: %2") 
    136163            .arg(name).arg(value)); 
    137164} 
     
    227254        ResetForNewFile(); 
    228255 
    229256        m_videoAspect = m_videoWidth = m_videoHeight = 0; 
    230  
     257         
     258    if (doTranscode) 
     259    { 
     260        VERBOSE(VB_RECORD,  LOC + "Waiting for transcoder to finish..."); 
     261        transcoder->wait(); 
     262        VERBOSE(VB_RECORD,  LOC + "Transcoder finished!"); 
     263        delete transcoder; 
     264        transcoder = NULL; 
     265    } 
     266                                                    
    231267        if (weMadeBuffer && ringBuffer) 
    232268            delete ringBuffer; 
    233269        SetRingBuffer(nextRingBuffer); 
  • libs/libmythtv/transcoder.cpp

     
     1// -*- Mode: c++ -*- 
     2/* 
     3 *  Copyright (C) Rene Buehlmann 2009 
     4 * 
     5 *  Copyright notice is in dvbrecorder.cpp of the MythTV project. 
     6 */ 
     7 
     8#include "transcoder.h" 
     9#include "mythverbose.h" 
     10#include "format.h" 
     11#include <stdio.h> 
     12#include <string.h> 
     13 
     14#define LOC QString("Transcoder: ") 
     15#define LOC_ERR QString("Transcoder Error: ") 
     16 
     17// AVLib/FFMPEG includes 
     18extern "C" 
     19{ 
     20#include "libavcodec/avcodec.h" 
     21#include "libavformat/avformat.h" 
     22#include "libavformat/mpegts.h" 
     23#include "libswscale/swscale.h" 
     24} 
     25 
     26static int rb_open(URLContext *h, const char *filename, int flags) 
     27{ 
     28    h->priv_data = (char *) strtoul(filename + 3, NULL, 16); 
     29    h->is_streamed = true; 
     30    return 0; 
     31} 
     32 
     33static int rb_read(URLContext *h, unsigned char *buf, int size) 
     34{ 
     35    RealRingBuffer *rb = (RealRingBuffer *) h->priv_data; 
     36    int len = rb->Read(buf, size); 
     37    return len; 
     38} 
     39 
     40static int rb_write(URLContext *h, unsigned char *buf, int size) 
     41{ 
     42    RealRingBuffer *rb = (RealRingBuffer *) h->priv_data; 
     43    return rb->Write(buf, size); 
     44} 
     45 
     46static int rb_close(URLContext *h) 
     47{ 
     48    return 0; 
     49} 
     50 
     51static int rb1_open(URLContext *h, const char *filename, int flags) 
     52{ 
     53    h->priv_data = (char *) strtoul(filename + 3, NULL, 16); 
     54    h->is_streamed = true; 
     55    return 0; 
     56} 
     57 
     58static int rb1_read(URLContext *h, unsigned char *buf, int size) 
     59{ 
     60    RingBuffer *rb = (RingBuffer *) h->priv_data; 
     61    int len = rb->Read(buf, size); 
     62    return len; 
     63} 
     64 
     65static int rb1_write(URLContext *h, unsigned char *buf, int size) 
     66{ 
     67    RingBuffer *rb = (RingBuffer *) h->priv_data; 
     68    return rb->Write(buf, size); 
     69} 
     70 
     71static int rb1_close(URLContext *h) 
     72{ 
     73    RingBuffer *rb = (RingBuffer *) h->priv_data; 
     74    rb->WriterFlush(); 
     75    return 0; 
     76} 
     77 
     78static int64_t rb1_seek(URLContext *h, int64_t os, int pos) 
     79{ 
     80    return 0; 
     81} 
     82 
     83URLProtocol rb_protocol = 
     84{ "rb", rb_open, rb_read, rb_write, NULL, rb_close, }; 
     85 
     86URLProtocol rb1_protocol = 
     87{ "rc", rb1_open, rb1_read, rb1_write, rb1_seek, rb1_close, }; 
     88 
     89Transcoder::Transcoder(RingBuffer *rb1, std::string a) : 
     90    name(a) 
     91{ 
     92    av_register_all(); 
     93    register_protocol(&rb_protocol); 
     94    register_protocol(&rb1_protocol); 
     95    ringBuffer = new RealRingBuffer(1024* 1024 ); //Let's try it with 1 MB... We might need to increase this. 
     96    rb = rb1; 
     97    vcodec = CODEC_ID_MPEG2VIDEO; 
     98    acodec = CODEC_ID_MP2; 
     99    transcode_video=true; 
     100    transcode_audio=true; 
     101} 
     102 
     103Transcoder::~Transcoder() 
     104{ 
     105    delete ringBuffer; 
     106} 
     107 
     108void Transcoder::setParam(const QString &name, int value) 
     109{ 
     110    if (name == "videobitrate") 
     111    { 
     112        videobitrate = value; 
     113    } 
     114    else if (name == "height") 
     115    { 
     116        height = value; 
     117    } 
     118    else if (name == "width") 
     119    { 
     120        width = value; 
     121    } 
     122    else if (name == "audiobitrate") 
     123    { 
     124        audiobitrate = value; 
     125    } 
     126} 
     127 
     128void Transcoder::setParam(const QString &name, const QString &value) 
     129{ 
     130    if (name == "videocodec") 
     131    { 
     132        if (value == "mpeg4") 
     133        { 
     134            vcodec = CODEC_ID_MPEG4; 
     135        } 
     136        else if (value == "wmv2") 
     137        { 
     138            vcodec = CODEC_ID_WMV2; 
     139        } 
     140        else if (value == "mpeg2") 
     141        { 
     142            vcodec = CODEC_ID_MPEG2VIDEO; 
     143        } 
     144        else 
     145        { 
     146            transcode_video = false; 
     147        } 
     148    } 
     149    else if (name == "audiocodec") 
     150    { 
     151        if (value == "mp2") 
     152        { 
     153            acodec = CODEC_ID_MP2; 
     154        } 
     155        if (value == "wmav2") 
     156        { 
     157            acodec = CODEC_ID_WMAV2; 
     158        } 
     159        else 
     160        { 
     161            transcode_audio = false; 
     162        } 
     163    } 
     164} 
     165 
     166void Transcoder::run() 
     167{ 
     168    int i; 
     169    AVPacket packet; 
     170    AVFormatContext *pFormatCtxDecode; 
     171    AVFormatContext *pFormatCtxEncode; 
     172    SwsContext *scaleContext; 
     173 
     174    // Open video 
     175    char buf[30]; 
     176    sprintf((char *) &buf, "rb:%p", ringBuffer); 
     177    if (av_open_input_file(&pFormatCtxDecode, (char *) &buf, NULL, 0, NULL) 
     178            != 0) 
     179    { 
     180        return; // Couldn't open file 
     181    } 
     182 
     183    // Retrieve stream information 
     184    if (av_find_stream_info(pFormatCtxDecode) < 0) 
     185        return; // Couldn't find stream information 
     186 
     187    // Dump information about file onto standard error 
     188    dump_format(pFormatCtxDecode, 0, (char *) &buf, false); 
     189    pFormatCtxDecode->flags |= AVFMT_NOFILE | AVFMT_FLAG_IGNIDX 
     190            | AVFMT_NOTIMESTAMPS; 
     191 
     192    //Prepare Output 
     193    pFormatCtxEncode = av_alloc_format_context(); 
     194    pFormatCtxEncode->oformat = guess_format("mpegts", NULL, NULL); 
     195    pFormatCtxEncode->flags |= AVFMT_NOFILE | AVFMT_FLAG_IGNIDX 
     196            | AVFMT_NOTIMESTAMPS; 
     197    sprintf((char *) &buf, "rc:%p", rb); 
     198    memcpy(pFormatCtxEncode->filename, (char *) &buf, 
     199            sizeof(pFormatCtxEncode->filename)); 
     200 
     201    //Prepare Video Codec 
     202    AVCodec *pVideoCodecEncode = avcodec_find_encoder(vcodec); 
     203    if (pVideoCodecEncode == NULL) 
     204    { 
     205        VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not open video encoder!\n"); 
     206        return; 
     207    } 
     208 
     209    //Prepare Audio Codec 
     210    AVCodec *pAudioCodecEncode = avcodec_find_encoder(acodec); 
     211    if (pAudioCodecEncode == NULL) 
     212    { 
     213        VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not open audio encoder!\n"); 
     214        return; 
     215    } 
     216 
     217    // Copy the streams 
     218    for (i = 0; i < pFormatCtxDecode->nb_streams; i++) 
     219    { 
     220        AVStream *ist = pFormatCtxDecode->streams[i]; 
     221        AVStream *ost = av_new_stream(pFormatCtxEncode, i); 
     222 
     223        if ((ist->codec->codec_type == CODEC_TYPE_VIDEO) && transcode_video) 
     224        { 
     225            ost->codec = avcodec_alloc_context(); 
     226            ost->codec->codec_type = ist->codec->codec_type; 
     227            ost->codec->bit_rate = videobitrate * 1000; 
     228            ost->codec->ildct_cmp = ist->codec->ildct_cmp; 
     229            ost->codec->sample_aspect_ratio.num 
     230                    = ist->codec->sample_aspect_ratio.num; 
     231            ost->codec->sample_aspect_ratio.den 
     232                    = ist->codec->sample_aspect_ratio.den; 
     233            ost->sample_aspect_ratio.num = ist->codec->sample_aspect_ratio.num; 
     234            ost->sample_aspect_ratio.den = ist->codec->sample_aspect_ratio.den; 
     235            ost->codec->width = ist->codec->width; 
     236            ost->codec->height = ist->codec->height; 
     237            if (!ost->codec->width) 
     238                ost->codec->width = 720; 
     239            if (!ost->codec->height) 
     240                ost->codec->height = 576; 
     241            ost->codec->pix_fmt = ist->codec->pix_fmt; 
     242 
     243            if (height != 0 && width != 0 && (ost->codec->width != width 
     244                    || ost->codec->height != height)) 
     245            { 
     246                ost->codec->width = width; 
     247                ost->codec->height = height; 
     248                scaleContext = sws_getContext(ist->codec->width, 
     249                        ist->codec->height, ist->codec->pix_fmt, width, height, 
     250                        ost->codec->pix_fmt, 1, NULL, NULL, NULL); 
     251                if (!scaleContext) 
     252                { 
     253                    VERBOSE(VB_IMPORTANT, LOC_ERR 
     254                            + "Could not create scale context!\n"); 
     255                    return; 
     256                } 
     257            } 
     258 
     259            ost->codec->gop_size = 10; // emit one intra frame every ten frames 
     260            ost->codec->max_b_frames = 5; 
     261            if (vcodec == CODEC_ID_WMV2) 
     262            { 
     263                ost->codec->max_b_frames = 0; //WMV2 does not accept b-frames 
     264            } 
     265 
     266            //if(av_q2d(ist->codec->time_base) > av_q2d(ist->time_base) && 
     267            //        av_q2d(ist->time_base) < 1.0/1000) 
     268            //    ost->codec->time_base = ist->codec->time_base; 
     269            //else 
     270            //ost->codec->time_base = ist->codec->time_base; 
     271            //ost->time_base = ist->codec->time_base; 
     272            //fixed framerate for now 
     273            ost->time_base.num=1; 
     274            ost->time_base.den=25; 
     275            ost->codec->time_base.num=1; 
     276            ost->codec->time_base.den=25; 
     277 
     278            if (avcodec_open(ost->codec, pVideoCodecEncode) < 0) 
     279            { 
     280                fprintf(stderr, "could not open video codec!!!\n"); 
     281                return; 
     282            } 
     283 
     284            AVCodec *pCodecDecode = avcodec_find_decoder(ist->codec->codec_id); 
     285            if (pCodecDecode == NULL) 
     286            { 
     287                VERBOSE(VB_IMPORTANT, LOC_ERR 
     288                        + "Could not open video decoder!\n"); 
     289                return; 
     290            } 
     291 
     292            if (avcodec_open(ist->codec, pCodecDecode) < 0) 
     293            { 
     294                VERBOSE(VB_IMPORTANT, LOC_ERR 
     295                        + "Could not open video decoder!\n"); 
     296                return; 
     297            } 
     298 
     299        } 
     300        else if ((ist->codec->codec_type == CODEC_TYPE_AUDIO) 
     301                && transcode_audio) 
     302        { 
     303            ost->codec = avcodec_alloc_context(); 
     304            ost->codec->codec_type = ist->codec->codec_type; 
     305            ost->codec->bit_rate = audiobitrate * 1000; 
     306            ost->codec->me_method = ist->codec->me_method; 
     307            ost->codec->sample_fmt = ist->codec->sample_fmt; 
     308            if (!ost->codec->width) 
     309                ost->codec->width = 720; 
     310            if (!ost->codec->height) 
     311                ost->codec->height = 576; 
     312 
     313            //if(!ost->codec->codec_tag){ 
     314            //    if(  pFormatCtxEncode->oformat->codec_tag 
     315            //        || av_codec_get_id (pFormatCtxEncode->oformat->codec_tag, ist->codec->codec_tag) > 0 
     316            //        || av_codec_get_tag(pFormatCtxEncode->oformat->codec_tag, ist->codec->codec_id) <= 0) 
     317            //        ost->codec->codec_tag = ist->codec->codec_tag; 
     318            //} 
     319 
     320            ost->codec->extradata = ist->codec->extradata; 
     321            ost->codec->extradata_size = ist->codec->extradata_size; 
     322 
     323            if (av_q2d(ist->codec->time_base) > av_q2d(ist->time_base) 
     324                    && av_q2d(ist->time_base) < 1.0 / 1000) 
     325                ost->codec->time_base = ist->codec->time_base; 
     326            else 
     327                ost->codec->time_base = ist->time_base; 
     328 
     329            ost->codec->sample_rate = 48000; 
     330            ost->codec->channels = ist->codec->channels ? ist->codec->channels 
     331                    : 2; 
     332            ost->codec->block_align = 0; 
     333 
     334            if (avcodec_open(ost->codec, pAudioCodecEncode) < 0) 
     335            { 
     336                fprintf(stderr, "could not open audio codec!!!\n"); 
     337                return; 
     338            } 
     339 
     340            AVCodec *pCodecDecode = avcodec_find_decoder(ist->codec->codec_id); 
     341            if (pCodecDecode == NULL) 
     342            { 
     343                VERBOSE(VB_IMPORTANT, LOC_ERR 
     344                        + "Could not open audio decoder!\n"); 
     345                return; 
     346            } 
     347 
     348            if (avcodec_open(ist->codec, pCodecDecode) < 0) 
     349            { 
     350                VERBOSE(VB_IMPORTANT, LOC_ERR 
     351                        + "Could not open audio decoder!\n"); 
     352                return; 
     353            } 
     354 
     355        } 
     356        else 
     357        { 
     358            ost->stream_copy = 1; 
     359            ost->codec->codec_id = ist->codec->codec_id; 
     360            ost->codec->codec_type = ist->codec->codec_type; 
     361            ost->codec->codec_tag = ist->codec->codec_tag; 
     362            memcpy(ost->codec->codec_name, ist->codec->codec_name, 
     363                    sizeof(ost->codec->codec_name)); 
     364            ost->codec->sub_id = ist->codec->sub_id; 
     365            ost->codec->me_method = ist->codec->me_method; 
     366            ost->codec->sample_fmt = ist->codec->sample_fmt; 
     367 
     368            //if(!ost->codec->codec_tag){ 
     369            //    if(  pFormatCtxEncode->oformat->codec_tag 
     370            //        || av_codec_get_id (pFormatCtxEncode->oformat->codec_tag, ist->codec->codec_tag) > 0 
     371            //        || av_codec_get_tag(pFormatCtxEncode->oformat->codec_tag, ist->codec->codec_id) <= 0) 
     372            //        ost->codec->codec_tag = ist->codec->codec_tag; 
     373            //} 
     374 
     375            ost->codec->bit_rate = ist->codec->bit_rate; 
     376            ost->codec->extradata = ist->codec->extradata; 
     377            ost->codec->extradata_size = ist->codec->extradata_size; 
     378 
     379            if (av_q2d(ist->codec->time_base) > av_q2d(ist->time_base) 
     380                    && av_q2d(ist->time_base) < 1.0 / 1000) 
     381                ost->codec->time_base = ist->codec->time_base; 
     382            else 
     383                ost->codec->time_base = ist->time_base; 
     384 
     385            switch (ost->codec->codec_type) 
     386            { 
     387            case CODEC_TYPE_AUDIO: 
     388                ost->codec->sample_rate 
     389                        = ist->codec->sample_rate ? ist->codec->sample_rate 
     390                                : 48000; 
     391                ost->codec->channels 
     392                        = ist->codec->channels ? ist->codec->channels : 2; 
     393                ost->codec->frame_size = ist->codec->frame_size; 
     394                ost->codec->block_align = ist->codec->block_align; 
     395                if (ost->codec->block_align == 1 && ost->codec->codec_id 
     396                        == CODEC_ID_MP3) 
     397                    ost->codec->block_align = 0; 
     398                break; 
     399            case CODEC_TYPE_VIDEO: 
     400                ost->codec->pix_fmt = ist->codec->pix_fmt; 
     401                ost->codec->width = ist->codec->width; 
     402                ost->codec->height = ist->codec->height; 
     403                ost->codec->has_b_frames = ist->codec->has_b_frames; 
     404                if (!ost->codec->width) 
     405                    ost->codec->width = 720; 
     406                if (!ost->codec->height) 
     407                    ost->codec->height = 576; 
     408                break; 
     409            case CODEC_TYPE_SUBTITLE: 
     410                break; 
     411            default: 
     412                break; 
     413            } 
     414 
     415            ost->pts.num = ist->pts.num; 
     416            ost->pts.den = ist->pts.den; 
     417        } 
     418    } 
     419 
     420    dump_format(pFormatCtxEncode, i, pFormatCtxEncode->filename, 1); 
     421    url_fopen(&pFormatCtxEncode->pb, pFormatCtxEncode->filename, URL_WRONLY); 
     422    av_write_header(pFormatCtxEncode); 
     423 
     424    AVFrame *pFrame = avcodec_alloc_frame(); 
     425    AVFrame *newFrame = pFrame; 
     426    int frameFinished; 
     427    int outbuf_size = 100000; 
     428    uint8_t *outbuf = new uint8_t[outbuf_size]; 
     429    int audiosamplesize = AVCODEC_MAX_AUDIO_FRAME_SIZE; 
     430    int16_t *audiosample = new int16_t[audiosamplesize]; 
     431 
     432    //For scaling 
     433    AVPicture *newPicture; 
     434    uint8_t *buffer; 
     435    if (scaleContext) 
     436    { 
     437        int numBytes = avpicture_get_size( 
     438                pFormatCtxEncode->streams[0]->codec->pix_fmt, width, height); 
     439        buffer = new uint8_t[numBytes]; 
     440        memset(buffer, 0, numBytes); 
     441        newPicture = new AVPicture(); 
     442        newFrame = avcodec_alloc_frame(); 
     443        avpicture_fill((AVPicture *) newPicture, buffer, 
     444                pFormatCtxEncode->streams[0]->codec->pix_fmt, width, height); 
     445    } 
     446 
     447    //Copy or Transcode 
     448    while (av_read_frame(pFormatCtxDecode, &packet) >= 0) 
     449    { 
     450        //only two streams for now.. 
     451        if (packet.stream_index > 2) 
     452        { 
     453            continue; 
     454        } 
     455        if (pFormatCtxEncode->streams[packet.stream_index]->stream_copy) 
     456        { 
     457            if (av_write_frame(pFormatCtxEncode, &packet)) 
     458                VERBOSE(VB_RECORD, LOC + "Write frame failed!\n"); 
     459        } 
     460        else 
     461        { 
     462            if (pFormatCtxDecode->streams[packet.stream_index]->codec->codec_type 
     463                    == CODEC_TYPE_VIDEO) 
     464            { 
     465                avcodec_decode_video( 
     466                        pFormatCtxDecode->streams[packet.stream_index]->codec, 
     467                        pFrame, &frameFinished, packet.data, packet.size); 
     468                if (frameFinished) 
     469                { 
     470                    //Do rescale? 
     471                    if (scaleContext) 
     472                    { 
     473                        sws_scale( 
     474                                scaleContext, 
     475                                pFrame->data, 
     476                                pFrame->linesize, 
     477                                0, 
     478                                pFormatCtxDecode->streams[packet.stream_index]->codec->height, 
     479                                newPicture->data, newPicture->linesize); 
     480                        newFrame->data[0] = newPicture->data[0]; 
     481                        newFrame->linesize[0] = newPicture->linesize[0]; 
     482                        newFrame->data[1] = newPicture->data[1]; 
     483                        newFrame->linesize[1] = newPicture->linesize[1]; 
     484                        newFrame->data[2] = newPicture->data[2]; 
     485                        newFrame->linesize[2] = newPicture->linesize[2]; 
     486                        newFrame->data[3] = newPicture->data[3]; 
     487                        newFrame->linesize[3] = newPicture->linesize[3]; 
     488                    } 
     489 
     490                    int 
     491                            out_size = 
     492                                    avcodec_encode_video( 
     493                                            pFormatCtxEncode->streams[packet.stream_index]->codec, 
     494                                            outbuf, outbuf_size, 
     495                                            (AVFrame*) newFrame); 
     496                    packet.data = outbuf; 
     497                    packet.size = out_size; 
     498                    av_write_frame(pFormatCtxEncode, &packet); 
     499                } 
     500            } 
     501            else 
     502            { 
     503                audiosamplesize = AVCODEC_MAX_AUDIO_FRAME_SIZE; 
     504                avcodec_decode_audio2( 
     505                        pFormatCtxDecode->streams[packet.stream_index]->codec, 
     506                        audiosample, &audiosamplesize, packet.data, packet.size); 
     507                int out_size = avcodec_encode_audio( 
     508                        pFormatCtxEncode->streams[packet.stream_index]->codec, 
     509                        outbuf, outbuf_size, audiosample); 
     510                packet.data = outbuf; 
     511                packet.size = out_size; 
     512                av_write_frame(pFormatCtxEncode, &packet); 
     513 
     514            } 
     515        } 
     516    } 
     517    if (scaleContext) 
     518    { 
     519        sws_freeContext(scaleContext); 
     520        delete buffer; 
     521        delete newPicture; 
     522    } 
     523    av_free_packet(&packet); 
     524    delete pFrame; 
     525    delete pFormatCtxEncode; 
     526    delete pFormatCtxDecode; 
     527    delete outbuf; 
     528    delete audiosample; 
     529    return; 
     530} 
     531 
  • libs/libmythtv/dtvrecorder.cpp

     
    104104            VERBOSE(VB_IMPORTANT, LOC_ERR + 
    105105                    "Could not allocate new packet buffer."); 
    106106    } 
     107    else 
     108    { 
     109       RecorderBase::SetOption(name, value); 
     110    } 
    107111} 
    108112 
    109113/** \fn DTVRecorder::FinishRecording(void) 
     
    116120    { 
    117121        if (_payload_buffer.size()) 
    118122        { 
    119             ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     123            if (doTranscode) 
     124            { 
     125                transcoder->ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     126            } 
     127            else 
     128            { 
     129                ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     130            } 
    120131            _payload_buffer.clear(); 
    121132        } 
    122         ringBuffer->WriterFlush(); 
     133        if (doTranscode) 
     134        { 
     135            transcoder->ringBuffer->SetEOF(); 
     136        } 
     137        else 
     138        { 
     139            ringBuffer->WriterFlush(); 
     140        } 
    123141    } 
    124142 
    125143    if (curRecording) 
     
    193211    // we have to write them first... 
    194212    if (!_payload_buffer.empty()) 
    195213    { 
    196         if (ringBuffer) 
     214        if (doTranscode) 
     215        { 
     216            transcoder->ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     217        } 
     218        else 
     219        { 
    197220            ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     221        } 
    198222        _payload_buffer.clear(); 
    199223    } 
    200224 
    201225    if (ringBuffer) 
    202         ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 
     226        if (doTranscode) 
     227        { 
     228            transcoder->ringBuffer->Write((unsigned char*)tspacket.data(), TSPacket::SIZE); 
     229        } 
     230        else 
     231        { 
     232            ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 
     233        } 
    203234} 
    204235 
    205236/** \fn DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 
     
    401432    SavePositionMap(true); 
    402433    if (ringBuffer) 
    403434    { 
    404         ringBuffer->WriterFlush(); 
     435        if (doTranscode) 
     436        { 
     437            transcoder->ringBuffer->SetEOF(); 
     438        } 
     439        else 
     440        { 
     441            ringBuffer->WriterFlush(); 
     442        } 
    405443        if (curRecording) 
    406444            curRecording->SetFilesize(ringBuffer->GetRealFileSize()); 
    407445    } 
     
    736774            { 
    737775                if (ringBuffer) 
    738776                { 
    739                     ringBuffer->Write( 
    740                         &_payload_buffer[0], _payload_buffer.size()); 
     777                    if (doTranscode) { 
     778                        transcoder->ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     779                    } 
     780                    else { 
     781                        ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 
     782                    } 
     783 
    741784                } 
    742785                _payload_buffer.clear(); 
    743786            } 
    744787 
    745788            if (ringBuffer) 
    746                 ringBuffer->Write(bufstart, (bufptr - bufstart)); 
     789                if (doTranscode) 
     790                { 
     791                    transcoder->ringBuffer->Write((unsigned char*)bufstart, (bufptr - bufstart)); 
     792                } 
     793                else 
     794                { 
     795                    ringBuffer->Write(bufstart, (bufptr - bufstart)); 
     796                } 
    747797 
    748798            bufstart = bufptr; 
    749799        } 
  • libs/libmythtv/recorderbase.h

     
    1111#include <pthread.h> 
    1212 
    1313#include "mythexp.h" 
     14#include "transcoder.h" 
    1415 
    1516class TVRec; 
    1617class RingBuffer; 
     
    257258    bool           weMadeBuffer; 
    258259 
    259260    QString        videocodec; 
     261    QString        audiocodec; 
    260262    QString        audiodevice; 
    261263    QString        videodevice; 
    262264    QString        vbidevice; 
    263265 
     266    int            videobitrate; 
     267    int            audiobitrate; 
    264268    int            vbimode; 
    265269    bool           ntsc; 
    266270    bool           ntsc_framerate; 
     
    290294    PosMap         positionMap; 
    291295    PosMap         positionMapDelta; 
    292296 
     297    //Transcode 
     298    bool           doTranscode; 
     299    Transcoder    *transcoder; 
     300 
    293301}; 
    294302 
    295303#endif 
  • libs/libmythtv/RealRingBuffer.h

     
     1// -*- Mode: c++ -*- 
     2/* 
     3 *  Copyright (C) Rene Buehlmann 2009 
     4 *   
     5 *  Copyright notice is in dvbrecorder.cpp of the MythTV project. 
     6 */ 
     7 
     8#ifndef REALRINGBUFFER_H 
     9#define REALRINGBUFFER_H 
     10 
     11#include <qthread.h> 
     12#include <qmutex.h> 
     13#include <qwaitcondition.h> 
     14 
     15using namespace std; 
     16 
     17class RealRingBuffer 
     18{ 
     19public: 
     20    RealRingBuffer(int size); 
     21    ~RealRingBuffer(); 
     22    int Write(unsigned char *buf, int len); 
     23    int Read(unsigned char *buf, int len); 
     24    void SetEOF(); 
     25    bool IsEOF(); 
     26private: 
     27    char *rb; 
     28    int rbsize; 
     29    int rbrpos; 
     30    int rbwpos; 
     31    int bytes; 
     32    bool eof; 
     33    QMutex mutex; 
     34    QWaitCondition needData; 
     35    QWaitCondition needSpace; 
     36}; 
     37 
     38#endif 
     39 
  • libs/libmythtv/recordingprofile.cpp

     
    528528    }; 
    529529}; 
    530530 
     531 
     532class VideoBitrate : public SliderSetting, public CodecParamStorage 
     533{ 
     534  public: 
     535    VideoBitrate(const RecordingProfile &parent) : 
     536        SliderSetting(this, 100, 8000, 100), 
     537        CodecParamStorage(this, parent, "videobitrate") 
     538    { 
     539        setLabel(QObject::tr("Video Bitrate")); 
     540        setValue(2200); 
     541        setHelpText(QObject::tr("Bitrate in kilobits/second.  2200Kbps is " 
     542                    "approximately 1 Gigabyte per hour.")); 
     543    }; 
     544}; 
     545 
     546class AudioBitrate : public SliderSetting, public CodecParamStorage 
     547{ 
     548  public: 
     549    AudioBitrate(const RecordingProfile &parent) : 
     550        SliderSetting(this, 32, 320, 16), 
     551        CodecParamStorage(this, parent, "audiobitrate") 
     552    { 
     553        setLabel(QObject::tr("Audio Bitrate")); 
     554        setValue(2200); 
     555        setHelpText(QObject::tr("Bitrate in kilobits/second.")); 
     556    }; 
     557}; 
     558 
     559class VideoCodec : public ComboBoxSetting, public CodecParamStorage 
     560{ 
     561  public: 
     562    VideoCodec(const RecordingProfile &parent) : 
     563        ComboBoxSetting(this), 
     564        CodecParamStorage(this, parent, "videocodec") 
     565    { 
     566        setLabel(QObject::tr("Video Codec")); 
     567 
     568        addSelection("mpeg2"); 
     569        addSelection("mpeg4"); 
     570        addSelection("wmv2"); 
     571        setValue(0); 
     572        setHelpText(QObject::tr("Sets the video codec.")); 
     573    }; 
     574}; 
     575 
     576class AudioCodec : public ComboBoxSetting, public CodecParamStorage 
     577{ 
     578  public: 
     579    AudioCodec(const RecordingProfile &parent) : 
     580        ComboBoxSetting(this), 
     581        CodecParamStorage(this, parent, "audiocodec") 
     582    { 
     583        setLabel(QObject::tr("Audio Codec")); 
     584 
     585        addSelection("mp2"); 
     586        addSelection("wmav2"); 
     587 
     588        setValue(0); 
     589        setHelpText(QObject::tr("Sets the audio codec.")); 
     590    }; 
     591}; 
     592 
     593 
     594class Transcode : public CheckBoxSetting, public CodecParamStorage 
     595{ 
     596  public: 
     597    Transcode(const RecordingProfile &parent) : 
     598        CheckBoxSetting(this), 
     599        CodecParamStorage(this, parent, "transcode") 
     600    { 
     601        setLabel(QObject::tr("Enable transcoding")); 
     602        setValue(true); 
     603        setHelpText(QObject::tr("If set, transcoding gets enabled.")); 
     604    }; 
     605}; 
     606 
     607 
    531608class ScaleBitrate : public CheckBoxSetting, public CodecParamStorage 
    532609{ 
    533610  public: 
     
    795872    }; 
    796873}; 
    797874 
     875class TranscoderSettings : public TriggeredConfigurationGroup 
     876{ 
     877  public: 
     878    TranscoderSettings(const RecordingProfile &parent, QString profName) : 
     879        TriggeredConfigurationGroup(false, true, false, false) 
     880    { 
     881        QString labelName; 
     882        labelName = QObject::tr("Transcoder"); 
     883        setName(labelName); 
     884 
     885        transcode = new Transcode(parent); 
     886        addChild(transcode); 
     887        setTrigger(transcode); 
     888 
     889        ConfigurationGroup* params = new VerticalConfigurationGroup(); 
     890        params->setLabel(QObject::tr("Video Parameters")); 
     891        params->addChild(new VideoCodec(parent)); 
     892        params->addChild(new VideoBitrate(parent)); 
     893 
     894        //addTarget("transcode", params); 
     895 
     896        //params = new VerticalConfigurationGroup(); 
     897        //params->setLabel(QObject::tr("Audio Parameters")); 
     898        params->addChild(new AudioCodec(parent)); 
     899        params->addChild(new AudioBitrate(parent)); 
     900 
     901        addTarget("transcode", params); 
     902 
     903    } 
     904 
     905private: 
     906    Transcode* transcode; 
     907}; 
     908 
     909 
    798910class VideoCompressionSettings : public TriggeredConfigurationGroup 
    799911{ 
    800912  public: 
     
    12901402    else if (type.toUpper() == "DVB") 
    12911403    { 
    12921404        addChild(new RecordingType(*this)); 
     1405        addChild(new TranscoderSettings(*this, profileName)); 
    12931406    } 
    12941407 
    12951408    id->setValue(profileId); 
  • libs/libmythtv/RealRingBuffer.cpp

     
     1// -*- Mode: c++ -*- 
     2/* 
     3 *  Copyright (C) Rene Buehlmann 2009 
     4 *   
     5 *  Copyright notice is in dvbrecorder.cpp of the MythTV project. 
     6 */ 
     7 
     8#include "RealRingBuffer.h" 
     9#include "mythverbose.h" 
     10 
     11#define LOC QString("RealRingBuffer: ") 
     12#define LOC_ERR QString("RealRingBuffer Error: ") 
     13 
     14RealRingBuffer::RealRingBuffer(int size) 
     15{ 
     16    rbsize = size; 
     17    eof = false; 
     18    rbrpos = 0; 
     19    rbwpos = 0; 
     20    bytes = 0; 
     21    rb = new char[size]; 
     22} 
     23 
     24RealRingBuffer::~RealRingBuffer() 
     25{ 
     26    delete rb; 
     27} 
     28 
     29bool RealRingBuffer::IsEOF() 
     30{ 
     31    return eof; 
     32} 
     33 
     34void RealRingBuffer::SetEOF() 
     35{ 
     36    QMutexLocker locker(&mutex); 
     37    eof = true; 
     38    needData.wakeAll(); 
     39} 
     40 
     41int RealRingBuffer::Read(unsigned char *buf, int size) 
     42{ 
     43    int len = 0; 
     44 
     45    QMutexLocker locker(&mutex); 
     46 
     47    if (eof && bytes == 0) 
     48    { 
     49        return -1; 
     50    } 
     51 
     52    while (size > 0) 
     53    { 
     54 
     55        if (bytes == 0) 
     56        { 
     57            if (eof) 
     58            { 
     59                return len; 
     60            } 
     61            needData.wait(&mutex); 
     62        } 
     63 
     64        int rby = bytes > size ? size : bytes; 
     65 
     66        if (rbrpos + rby > rbsize) 
     67        { 
     68            rby = rbsize - rbrpos; 
     69        } 
     70 
     71        memcpy(buf, rb + rbrpos, rby); 
     72        size -= rby; 
     73        buf += rby; 
     74        bytes -= rby; 
     75        len += rby; 
     76        rbrpos = (rbrpos + rby) % rbsize; 
     77        needSpace.wakeAll(); 
     78    } 
     79    return len; 
     80} 
     81 
     82int RealRingBuffer::Write(unsigned char *buf, int size) 
     83{ 
     84    int len = 0; 
     85    QMutexLocker locker(&mutex); 
     86 
     87    while (size > 0) 
     88    { 
     89 
     90        if (rbsize - bytes == 0) 
     91        { 
     92            VERBOSE(VB_RECORD, LOC 
     93                    + "Ringbuffer is full. Waiting for data read."); 
     94            needSpace.wait(&mutex); 
     95        } 
     96 
     97        int wb = rbsize - bytes > size ? size : rbsize - bytes; 
     98 
     99        if (rbwpos + wb > rbsize) 
     100        { 
     101            wb = rbsize - rbwpos; 
     102        } 
     103 
     104        memcpy(rb + rbwpos, buf, wb); 
     105        size -= wb; 
     106        buf += wb; 
     107        bytes += wb; 
     108        len += wb; 
     109        rbwpos = (rbwpos + wb) % rbsize; 
     110        needData.wakeAll(); 
     111    } 
     112    return len; 
     113}