Ticket #2581: 2581_aspectRatio-trunk.patch

File 2581_aspectRatio-trunk.patch, 17.4 KB (added by cpinkham, 11 years ago)

Aspect Ratio patch modified to work with trunk & with deinterlacing ability

  • libs/libmythtv/recordingprofile.cpp

     
    571571    };
    572572};
    573573
     574class MPEG4AspectRatio: public ComboBoxSetting, public CodecParamStorage {
     575public:
     576   MPEG4AspectRatio(const RecordingProfile& parent):
     577        ComboBoxSetting(this),
     578        CodecParamStorage(this, parent, "mpeg4aspectratio") {
     579        setLabel(QObject::tr("Aspect Ratio"));
     580        addSelection(QObject::tr("Original", "Original"));
     581        addSelection(QObject::tr("Crop to 4:3", "4:3"));
     582        addSelection(QObject::tr("Crop to 16:9", "16:9"));
     583        setValue("Original");
     584        setHelpText(QObject::tr("Crop transcoded files to the indicated "
     585                                "aspect ratio"));
     586    };
     587};
     588
     589class MPEG4DeInterlace: public ComboBoxSetting, public CodecParamStorage {
     590public:
     591   MPEG4DeInterlace(const RecordingProfile& parent):
     592        ComboBoxSetting(this),
     593        CodecParamStorage(this, parent, "mpeg4deinterlace") {
     594        setLabel(QObject::tr("DeInterlace"));
     595        addSelection(QObject::tr("No", "0"));
     596        addSelection(QObject::tr("Yes", "1"));
     597        setValue("0");
     598        setHelpText(QObject::tr("DeInterlace video when resizing"));
     599    };
     600};
     601
    574602class MPEG4QualDiff : public SliderSetting, public CodecParamStorage
    575603{
    576604  public:
     
    822850
    823851        params = new VerticalConfigurationGroup(false);
    824852        params->setLabel(QObject::tr("MPEG-4 Parameters"));
    825         params->addChild(new MPEG4bitrate(parent));
    826         params->addChild(new MPEG4MaxQuality(parent));
    827         params->addChild(new MPEG4MinQuality(parent));
     853
     854        HorizontalConfigurationGroup *hbr;
     855        hbr = new HorizontalConfigurationGroup(false, false);
     856        hbr->addChild(new MPEG4bitrate(parent));
     857        hbr->addChild(new ScaleBitrate(parent));
     858        params->addChild(hbr);
     859
     860        HorizontalConfigurationGroup *hmmq;
     861        hmmq = new HorizontalConfigurationGroup(false, false);
     862        hmmq->addChild(new MPEG4MaxQuality(parent));
     863        hmmq->addChild(new MPEG4MinQuality(parent));
     864        params->addChild(hmmq);
     865
    828866        params->addChild(new MPEG4QualDiff(parent));
    829         params->addChild(new ScaleBitrate(parent));
    830867
     868        HorizontalConfigurationGroup *hasp;
     869        hasp = new HorizontalConfigurationGroup(false, false);
     870        hasp->addChild(new MPEG4AspectRatio(parent));
     871        hasp->addChild(new MPEG4DeInterlace(parent));
     872        params->addChild(hasp);
     873
    831874        HorizontalConfigurationGroup *hq;
    832875        hq = new HorizontalConfigurationGroup(false, false);
    833876        hq->addChild(new MPEG4OptionVHQ(parent));
  • programs/mythtranscode/transcode.cpp

     
    3232#include "mythdbcon.h"
    3333
    3434
    35 extern "C" {
    36 #include "libavcodec/avcodec.h"
    37 #include "libswscale/swscale.h"
    38 }
    39 
    4035#define LOC QString("Transcode: ")
    4136#define LOC_ERR QString("Transcode, Error: ")
    4237
     
    248243    fifow(NULL),
    249244    kfa_table(NULL),
    250245    showprogress(false),
    251     recorderOptions("")   
     246    recorderOptions(""),
     247    m_deinterlace(false),
     248    m_scontext(NULL)
    252249{
    253250}
    254251
     
    268265        delete fifow;
    269266    if (kfa_table)
    270267        delete kfa_table;
     268
     269    if (m_deinterlace)
     270        avpicture_free(&m_imageDeInt);
     271    if (m_scontext)
     272        sws_freeContext(m_scontext);
    271273}
    272274void Transcode::ReencoderAddKFA(long curframe, long lastkey, long num_keyframes)
    273275{
     
    333335        // If a bad profile is specified, there will be trouble
    334336        if (isNum && profileID > 0)
    335337            profile.loadByID(profileID);
    336         else
     338        else if (!profile.loadByGroup(profileName, "Transcoders"))
    337339        {
    338340            VERBOSE(VB_IMPORTANT, QString("Couldn't find profile #: %1").
    339341                    arg(profileName));
     
    379381  nvr->WriteText(buf, len, timecode, pagenr);
    380382}
    381383
     384void Transcode::EncodeFrame(unsigned char *srcBuf, int srcWidth, int srcHeight,
     385                            unsigned char *dstBuf, int dstWidth, int dstHeight,
     386                            int cr_top, int cr_bottom,
     387                            int cr_left, int cr_right)
     388{
     389    avpicture_fill(&m_imageIn, srcBuf, PIX_FMT_YUV420P, srcWidth, srcHeight);
     390    avpicture_fill(&m_imageOut, dstBuf, PIX_FMT_YUV420P, dstWidth, dstHeight);
     391
     392    int bottomBand = (srcHeight == 1088) ? 8 : 0;
     393    if (cr_top || cr_bottom || cr_left || cr_right)
     394    {
     395        AVPicture *cropSrc = &m_imageIn;
     396        if (m_deinterlace)
     397        {
     398            cropSrc = &m_imageDeInt;
     399            avpicture_deinterlace(&m_imageDeInt, &m_imageIn, PIX_FMT_YUV420P,
     400                                  srcWidth, srcHeight);
     401        }
     402
     403        av_picture_crop(&m_imageCrop, cropSrc,
     404                        PIX_FMT_YUV420P, cr_top, cr_left);
     405
     406        m_scontext = sws_getCachedContext(m_scontext,
     407                       srcWidth - cr_left - cr_right,
     408                       srcHeight - cr_top - cr_bottom, PIX_FMT_YUV420P,
     409                       dstWidth, dstHeight, PIX_FMT_YUV420P,
     410                       SWS_FAST_BILINEAR, NULL, NULL, NULL);
     411        sws_scale(m_scontext, m_imageCrop.data, m_imageCrop.linesize, 0,
     412              srcHeight - bottomBand - cr_top - cr_bottom,
     413              m_imageOut.data, m_imageOut.linesize);
     414    }
     415    else
     416    {
     417
     418        m_scontext = sws_getCachedContext(m_scontext, srcWidth, srcHeight,
     419                                          PIX_FMT_YUV420P, dstWidth, dstHeight,
     420                                          PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
     421                                          NULL, NULL, NULL);
     422
     423        AVPicture *scaleSrc = &m_imageIn;
     424        if (m_deinterlace)
     425        {
     426            scaleSrc = &m_imageDeInt;
     427            avpicture_deinterlace(&m_imageDeInt, &m_imageIn, PIX_FMT_YUV420P,
     428                                  srcWidth, srcHeight);
     429        }
     430
     431        sws_scale(m_scontext, scaleSrc->data, scaleSrc->linesize, 0,
     432                  srcHeight - bottomBand, m_imageOut.data, m_imageOut.linesize);
     433    }
     434}
     435
    382436int Transcode::TranscodeFile(
    383437    const QString &inputname,
    384438    const QString &outputname,
     
    486540    QSize buf_size = nvp->GetVideoBufferSize();
    487541    int video_width = buf_size.width();
    488542    int video_height = buf_size.height();
    489      
     543
    490544    if (video_height == 1088) {
    491545       VERBOSE(VB_IMPORTANT, "Found video height of 1088.  This is unusual and "
    492546               "more than likely the video is actually 1080 so mythtranscode "
     
    498552    int newWidth = video_width;
    499553    int newHeight = video_height;
    500554
     555    video_aspect = 1.33333333;
     556
     557    VERBOSE(VB_IMPORTANT, QString("Transcode: current aspect ratio: %1")
     558                                  .arg(video_aspect));
     559
     560
     561    float newAspect  = video_aspect;
     562    float oldAspect  = video_aspect;
     563    int crop_top     = 0;
     564    int crop_bottom  = 0;
     565    int crop_left    = 0;
     566    int crop_right   = 0;
     567
    501568    kfa_table = new vector<struct kfatable_entry>;
    502569
    503570    if (fifodir.isEmpty())
     
    553620            newWidth = get_int_option(profile, "width");
    554621            newHeight = get_int_option(profile, "height");
    555622
     623            int profWidth = newWidth;
     624            int profHeight = newHeight;
     625
    556626            // If height or width are 0, then we need to calculate them
    557627            if (newHeight == 0 && newWidth > 0)
    558628                newHeight = (int)(1.0 * newWidth * actualHeight / video_width);
     
    569639                }
    570640            }
    571641
     642            if (vidsetting == "MPEG-4")
     643            {
     644                const Setting* setting = profile.byName("mpeg4aspectratio");
     645                if (setting)
     646                {
     647                    if (setting->getValue() == "4:3") {
     648                        VERBOSE(VB_IMPORTANT, QString(
     649                                "Transcoder calls for a 4:3 aspect ratio"));
     650                        newAspect = 1.333333333333;
     651                    } else if (setting->getValue() == "16:9") {
     652                        VERBOSE(VB_IMPORTANT, QString(
     653                                "Transcoder calls for a 16:9 aspect ratio"));
     654                        newAspect = 1.777777777777;
     655                    } else if (setting->getValue() == "Original") {
     656                        VERBOSE(VB_IMPORTANT, QString(
     657                                "Transcoder leaving aspect ratio unchanged"));
     658                    } else {
     659                        VERBOSE(VB_IMPORTANT, QString(
     660                                "Transcode unable to determine aspect ratio"));
     661                    }
     662
     663                    // if aspect ratios differ then crop the output
     664                    if (abs(newAspect - oldAspect) > 0.001) {
     665                        // calculate the actual pixel ratio for videos, needed
     666                        // when encoded without square pixels, such as 720x480
     667                        // NTSC captures
     668                        float pixelRatio =
     669                            float(video_width)/float(video_height)/oldAspect;
     670
     671                        // scale the aspect ratio by the pixel ratio
     672                        float newAspectScaling = newAspect * pixelRatio;
     673                        if (abs(oldAspect - 1.77777) < 0.001) {
     674                            if (!profWidth && profHeight)
     675                                newWidth = (int)(newHeight * newAspectScaling);
     676                            int scaledWidth =
     677                                (int)(video_height * newAspectScaling);
     678                            crop_left = (int)(video_width - scaledWidth) / 2;
     679                            crop_right = crop_left;
     680                        } else if (abs(oldAspect - 1.33333) < 0.01) {
     681                            if (profWidth && !profHeight)
     682                                newHeight = (int)(newWidth / newAspectScaling);
     683                            int scaledHeight =
     684                                (int)(video_width / newAspectScaling);
     685                            crop_top = (int)(video_height - scaledHeight) / 2;
     686                            crop_bottom = crop_top;
     687                        } else {
     688                            VERBOSE(VB_IMPORTANT, QString("Transcode: Unknown "
     689                                    "aspect ratio %1 on input video, video "
     690                                    "will not be cropped.").arg(oldAspect));
     691                            newAspect = oldAspect;
     692                        }
     693                    }
     694                } else {
     695                    VERBOSE(VB_IMPORTANT, QString("Transcode: Unable to "
     696                            "determine aspect ratio"));
     697                }
     698
     699                setting = profile.byName("mpeg4deinterlace");
     700                if (setting)
     701                    m_deinterlace = setting->getValue().toInt();
     702            }
     703
     704
    572705            if (encodingType.left(4).toLower() == "mpeg")
    573706            {
    574707                // make sure dimensions are valid for MPEG codecs
     
    579712            VERBOSE(VB_IMPORTANT, QString("Resizing from %1x%2 to %3x%4")
    580713                    .arg(video_width).arg(video_height)
    581714                    .arg(newWidth).arg(newHeight));
     715
     716            if (crop_top || crop_bottom || crop_left || crop_right)
     717                VERBOSE(VB_IMPORTANT, QString("Crop Settings %1 %2 %3 %4")
     718                        .arg(crop_left).arg(crop_right)
     719                        .arg(crop_top).arg(crop_bottom));
    582720        }
    583721        else  // lossy and no resize
    584722            nvp->SetVideoFilters(vidfilters);
     
    593731        nvr->SetOption("vbiformat", gContext->GetSetting("VbiFormat"));
    594732
    595733        nvr->SetFrameRate(video_frame_rate);
    596         nvr->SetVideoAspect(video_aspect);
     734        nvr->SetVideoAspect(newAspect);
    597735        nvr->SetTranscoding(true);
    598736
    599737        if ((vidsetting == "MPEG-4") ||
     
    804942    unsigned char *newFrame = new unsigned char[frame.size];
    805943
    806944    frame.buf = newFrame;
    807     AVPicture imageIn, imageOut;
    808     struct SwsContext  *scontext = NULL;
    809945
     946    if (m_deinterlace)
     947        avpicture_alloc(&m_imageDeInt, PIX_FMT_YUV420P,
     948                        video_width, video_height);
     949
    810950    if (fifow)
    811951        VERBOSE(VB_GENERAL, "Dumping Video and Audio data to fifos");
    812952    else if (copyaudio)
     
    9621102            if (! nvp->WriteStoredData(outRingBuffer, (did_ff == 0),
    9631103                                       timecodeOffset))
    9641104            {
    965                 if (video_aspect != nvp->GetVideoAspect())
     1105                if (oldAspect != nvp->GetVideoAspect())
    9661106                {
    9671107                    video_aspect = nvp->GetVideoAspect();
    968                     nvr->SetNewVideoParams(video_aspect);
     1108
     1109                    if (abs(video_aspect - oldAspect) < 0.001)
     1110                        nvr->SetNewVideoParams(newAspect);
     1111                    else
     1112                        nvr->SetNewVideoParams(video_aspect);
    9691113                }
    9701114
    9711115                QSize buf_size = nvp->GetVideoBufferSize();
     
    9961140                else
    9971141                {
    9981142                    frame.buf = newFrame;
    999                     avpicture_fill(&imageIn, lastDecode->buf, PIX_FMT_YUV420P,
    1000                                    video_width, video_height);
    1001                     avpicture_fill(&imageOut, frame.buf, PIX_FMT_YUV420P,
    1002                                    newWidth, newHeight);
    10031143
    1004                     int bottomBand = (video_height == 1088) ? 8 : 0;
    1005                     scontext = sws_getCachedContext(scontext, video_width,
    1006                                    video_height, PIX_FMT_YUV420P, newWidth,
    1007                                    newHeight, PIX_FMT_YUV420P,
    1008                                    SWS_FAST_BILINEAR, NULL, NULL, NULL);
    1009 
    1010                     sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
    1011                               video_height - bottomBand,
    1012                               imageOut.data, imageOut.linesize);
     1144                    EncodeFrame(lastDecode->buf, video_width, video_height,
     1145                                frame.buf, newWidth, newHeight,
     1146                                crop_top, crop_bottom, crop_left, crop_right);
    10131147                }
    10141148
    10151149                nvr->WriteVideo(&frame, true, writekeyframe);
     
    10291163            if (video_aspect != nvp->GetVideoAspect())
    10301164            {
    10311165                video_aspect = nvp->GetVideoAspect();
    1032                 nvr->SetNewVideoParams(video_aspect);
     1166                if (abs(video_aspect - oldAspect) < 0.001)
     1167                    nvr->SetNewVideoParams(newAspect);
     1168                else
     1169                    nvr->SetNewVideoParams(video_aspect);
    10331170            }
    10341171
    10351172
     
    10531190            else
    10541191            {
    10551192                frame.buf = newFrame;
    1056                 avpicture_fill(&imageIn, lastDecode->buf, PIX_FMT_YUV420P,
    1057                                video_width, video_height);
    1058                 avpicture_fill(&imageOut, frame.buf, PIX_FMT_YUV420P,
    1059                                newWidth, newHeight);
    10601193
    1061                 int bottomBand = (video_height == 1088) ? 8 : 0;
    1062                 scontext = sws_getCachedContext(scontext, video_width,
    1063                                video_height, PIX_FMT_YUV420P, newWidth,
    1064                                newHeight, PIX_FMT_YUV420P,
    1065                                SWS_FAST_BILINEAR, NULL, NULL, NULL);
    1066 
    1067                 sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
    1068                           video_height - bottomBand,
    1069                           imageOut.data, imageOut.linesize);
     1194                EncodeFrame(lastDecode->buf, video_width, video_height,
     1195                            frame.buf, newWidth, newHeight,
     1196                            crop_top, crop_bottom, crop_left, crop_right);
    10701197            }
    10711198
    10721199            // audio is fully decoded, so we need to reencode it
     
    11641291        frame.frameNumber = 1 + (curFrameNum << 1);
    11651292    }
    11661293
    1167     sws_freeContext(scontext);
    1168 
    11691294    if (! fifow)
    11701295    {
    11711296        if (m_proginfo)
  • programs/mythtranscode/transcode.h

     
    22#include "fifowriter.h"
    33#include "transcodedefs.h"
    44
     5extern "C" {
     6#include "libavcodec/avcodec.h"
     7#include "libswscale/swscale.h"
     8}
     9
    510class PlayerContext;
    611class ProgramInfo;
    712class NuppelVideoRecorder;
     
    2025        const QString &profileName,
    2126        bool honorCutList, bool framecontrol, int jobID,
    2227        QString fifodir, QMap<long long, int> deleteMap);
     28    void EncodeFrame(unsigned char *srcBuf, int srcWidth, int srcHeight,
     29                     unsigned char *dstBuf, int dstWidth, int dstHeight,
     30                     int cr_top, int cr_bottom, int cr_left, int cr_right);
    2331    void ShowProgress(bool val) { showprogress = val; }
    2432    void SetRecorderOptions(QString options) { recorderOptions = options; }
    2533
     
    4250    KFATable               *kfa_table;
    4351    bool                    showprogress;
    4452    QString                 recorderOptions;
     53
     54    AVPicture               m_imageIn;
     55    AVPicture               m_imageDeInt;
     56    AVPicture               m_imageCrop;
     57    AVPicture               m_imageOut;
     58    bool                    m_deinterlace;
     59    struct SwsContext      *m_scontext;
    4560};
    4661
    4762/* vim: set expandtab tabstop=4 shiftwidth=4: */