/*
 *  codec.c - Codec utilities for the tests
 *
 *  Copyright (C) 2013 Intel Corporation
 *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
 *
 *  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, 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 = codec_identifier_peek;
  tfp->suggest = 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;
}
