/*
 *  codec.c - Codec utilities for the tests
 *
 *  Copyright (C) 2013 Intel Corporation
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301 USA
 */

#include "gst/vaapi/sysdeps.h"
#include <gst/vaapi/gstvaapidisplay.h>
#include "codec.h"

typedef struct {
    const gchar *codec_str;
    GstVaapiCodec codec;
    const gchar *caps_str;
} CodecMap;

static const CodecMap g_codec_map[] = {
    { "h264",   GST_VAAPI_CODEC_H264,
      "video/x-h264" },
    { "jpeg",   GST_VAAPI_CODEC_JPEG,
      "image/jpeg" },
    { "mpeg2",  GST_VAAPI_CODEC_MPEG2,
      "video/mpeg, mpegversion=2" },
    { "mpeg4",  GST_VAAPI_CODEC_MPEG4,
      "video/mpeg, mpegversion=4" },
    { "wmv3",   GST_VAAPI_CODEC_VC1,
      "video/x-wmv, wmvversion=3" },
    { "vc1",    GST_VAAPI_CODEC_VC1,
      "video/x-wmv, wmvversion=3, " GST_MAKE_FORMAT_STRING(WVC1) },
    { NULL, }
};

static const CodecMap *
get_codec_map(GstVaapiCodec codec)
{
    const CodecMap *m;

    if (codec) {
        for (m = g_codec_map; m->codec_str != NULL; m++) {
            if (m->codec == codec)
                return m;
        }
    }
    return NULL;
}

const gchar *
string_from_codec(GstVaapiCodec codec)
{
    const CodecMap * const m = get_codec_map(codec);

    return m ? m->codec_str : NULL;
}

GstCaps *
caps_from_codec(GstVaapiCodec codec)
{
    const CodecMap * const m = get_codec_map(codec);

    return m ? gst_caps_from_string(m->caps_str) : NULL;
}

GstVaapiCodec
identify_codec_from_string(const gchar *codec_str)
{
    const CodecMap *m;

    if (codec_str) {
        for (m = g_codec_map; m->codec_str != NULL; m++) {
            if (g_ascii_strcasecmp(m->codec_str, codec_str) == 0)
                return m->codec;
        }
    }
    return 0;
}

typedef struct {
    GMappedFile *file;
    guint8      *data;
    guint        size;
    guint        probability;
    GstCaps     *caps;
    GstTypeFind  type_find;
} CodecIdentifier;

static const guint8 *
codec_identifier_peek(gpointer data, gint64 offset, guint size)
{
    CodecIdentifier * const cip = data;

    if (offset >= 0 && offset + size <= cip->size)
        return cip->data + offset;
    if (offset < 0 && ((gint)cip->size + offset) >= 0)
        return &cip->data[cip->size + offset];
    return NULL;
}

static void
codec_identifier_suggest(gpointer data, guint probability, GstCaps *caps)
{
    CodecIdentifier * const cip = data;

    if (cip->probability < probability) {
        cip->probability = probability;
        gst_caps_replace(&cip->caps, caps);
    }
}

static void
codec_identifier_free(CodecIdentifier *cip)
{
    if (!cip)
        return;

    if (cip->file) {
        g_mapped_file_unref(cip->file);
        cip->file = NULL;
    }
    gst_caps_replace(&cip->caps, NULL);
    g_slice_free(CodecIdentifier, cip);
}

static CodecIdentifier *
codec_identifier_new(const gchar *filename)
{
    CodecIdentifier *cip;
    GstTypeFind *tfp;

    cip = g_slice_new0(CodecIdentifier);
    if (!cip)
        return NULL;

    cip->file = g_mapped_file_new(filename, FALSE, NULL);
    if (!cip->file)
        goto error;

    cip->size = g_mapped_file_get_length(cip->file);
    cip->data = (guint8 *)g_mapped_file_get_contents(cip->file);
    if (!cip->data)
        goto error;

    tfp = &cip->type_find;
    tfp->peek = (GstTypeFindPeekFunction)codec_identifier_peek;
    tfp->suggest = (GstTypeFindSuggestFunction)codec_identifier_suggest;
    tfp->data = cip;
    return cip;

error:
    codec_identifier_free(cip);
    return NULL;
}

GstVaapiCodec
identify_codec(const gchar *filename)
{
    CodecIdentifier *cip;
    GList *type_list, *l;
    guint32 codec = 0;

    cip = codec_identifier_new(filename);
    if (!cip)
        return 0;

    type_list = gst_type_find_factory_get_list();
    for (l = type_list; l != NULL; l = l->next) {
        GstTypeFindFactory * const factory = GST_TYPE_FIND_FACTORY(l->data);
        gst_type_find_factory_call_function(factory, &cip->type_find);
    }
    g_list_free(type_list);

    if (cip->probability >= GST_TYPE_FIND_LIKELY)
        codec = gst_vaapi_profile_get_codec(
            gst_vaapi_profile_from_caps(cip->caps));

    codec_identifier_free(cip);
    return codec;
}