Ticket #6888: live_transcode.2.patch

File live_transcode.2.patch, 36.6 KB (added by buehlmann@…, 15 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}