/***************************************************************************
                           kdetvdscalerfilter.cpp
                           ----------------------
    begin                : Thu Jul 1 2004
    copyright            : (C) 2004 by Dirk Ziegelmeier
    email                : dziegel@gmx.de
***************************************************************************/

/*
 * kdetv to DScaler deinterlacer/filter API wrapper.
 */

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <kdebug.h>
#include <klocale.h>
#include <kconfig.h>
#include <string.h>
#include <QtGlobal>

#include "kdetvdscalerfilter.h"
#include "kdetvimagefilter.h"
#include "kdetvimagepool.h"
#include "kdetvimagefiltercontext.h"
#include "kdetvcpudetection.h"

KdetvDScalerFilter::KdetvDScalerFilter(const QString& name)
    : KdetvImageFilter(name)
{
}

KdetvDScalerFilter::~KdetvDScalerFilter()
{
}

KdetvImage::ImageFormat KdetvDScalerFilter::inputFormats()
{
    return KdetvImage::FORMAT_YUYV;
}

KdetvImageFilterContext* KdetvDScalerFilter::operator<< (KdetvImageFilterContext* ctx)
{
    // DScaler filters need an image history
    if(ctx->imageCount < 4) {
        return ctx;
    }

    ctx->out->deleteRef();
    ctx->out = ctx->imagesWithBuffer->getImage();
    ctx->out->setSize(ctx->images[0]->size());
    ctx->out->setFormat(ctx->images[0]->format());

    TPicture pictureHistory[dscalerHistory];
    TPicture* pictureHistoryPointers[dscalerHistory];
    TDeinterlaceInfo info;

    for(int i=0; i<qMin((int)dscalerHistory, (int)ctx->imageCount); i++) {
        pictureHistoryPointers[i] = &pictureHistory[i];
    }

    info.PictureHistory = pictureHistoryPointers;
    info.Overlay        = ctx->out->buffer();
    info.OverlayPitch   = ctx->out->bytesPerLine() + ctx->out->stride();
    info.LineLength     = ctx->images[0]->bytesPerLine();
    info.InputPitch     = ctx->images[0]->bytesPerLine() + ctx->images[0]->stride();
    info.FrameWidth     = ctx->images[0]->size().width();
    info.FrameHeight    = ctx->images[0]->size().height();
    info.FieldHeight    = ctx->images[0]->size().height() / 2;
    info.pMemcpy        = memcpy;

    for(int i=0; i<qMin((int)dscalerHistory, (int)ctx->imageCount); i++) {
        pictureHistory[i].pData = ctx->images[i]->buffer();

        if(ctx->images[i]->type() == KdetvImage::TYPE_INTERLACED_ODD) {
            pictureHistory[i].Flags = PICTURE_INTERLACED_ODD;
        } else {
            pictureHistory[i].Flags = PICTURE_INTERLACED_EVEN;
        }
    }

    KdetvCpuDetection::Capabilities cap = KdetvCpuDetection::capabilities();
    if(cap & KdetvCpuDetection::Cap_SSE2) {
        filterDScaler_SSE2(&info);
    } else if(cap & KdetvCpuDetection::Cap_3DNOW) {
        filterDScaler_3DNOW(&info);
    } else if(cap & KdetvCpuDetection::Cap_SSE) {
        filterDScaler_SSE(&info);
    } else if(cap & KdetvCpuDetection::Cap_MMX) {
        filterDScaler_MMX(&info);
    }
    return ctx;
}

void KdetvDScalerFilter::filterDScaler_3DNOW(TDeinterlaceInfo* pInfo)
{
    filterDScaler_MMX(pInfo);
}

void KdetvDScalerFilter::filterDScaler_SSE(TDeinterlaceInfo* pInfo)
{
    filterDScaler_MMX(pInfo);
}

void KdetvDScalerFilter::filterDScaler_SSE2(TDeinterlaceInfo* pInfo)
{
    filterDScaler_SSE(pInfo);
}
