/* * Copyright (c) 2007 Wayne Meissner * * This file is part of gstreamer-java. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code 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 * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see <http://www.gnu.org/licenses/>. */ package org.gstreamer; import static org.gstreamer.lowlevel.GlibAPI.GLIB_API; import java.util.AbstractList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.gstreamer.glib.GDate; import org.gstreamer.lowlevel.GType; import org.gstreamer.lowlevel.GstNative; import org.gstreamer.lowlevel.GstTagAPI; import org.gstreamer.lowlevel.GstTagListAPI; import org.gstreamer.lowlevel.annotations.CallerOwnsReturn; import com.sun.jna.Pointer; import com.sun.jna.ptr.PointerByReference; /** * List of tags and values used to describe media metadata. */ @SuppressWarnings("serial") public class TagList extends Structure { private static interface API extends GstTagListAPI, GstTagAPI { @CallerOwnsReturn Pointer ptr_gst_tag_list_new(); @CallerOwnsReturn Pointer ptr_gst_tag_list_copy(TagList list); @CallerOwnsReturn Pointer ptr_gst_tag_list_merge(TagList list1, TagList list2, TagMergeMode mode); void gst_tag_list_free(Pointer list); } private static final API gst = GstNative.load(API.class); /** * Creates a new instance of TagList * @param init internal initialization data. */ public TagList(Initializer init) { super(init); } /** * Constructs a new empty tag list. */ public TagList() { super(initializer(gst.ptr_gst_tag_list_new())); } /** * Gets the number of values of type {@code tag} stored in the list. * * @param tag the name of the tag to get the size of. * @return the number of values for {@code tag} in this list. */ public int getValueCount(String tag) { return gst.gst_tag_list_get_tag_size(this, tag); } /** * Gets all data values for a tag contained in this list. * * @param tag the name of the tag to retrieve. * @return the data associated with {@code tag}. */ public List<Object> getValues(final String tag) { final int size = getValueCount(tag); return new AbstractList<Object>() { @Override public int size() { return size; } @Override public Object get(int index) { return getValue(tag, index); } }; } /** * Gets all data values for a tag contained in this list. * * @param tag the name of the tag to retrieve. * @return the data associated with {@code tag}. */ public List<Object> getValues(Tag tag) { return getValues(tag.getId()); } /** * Gets data for a tag from this list. * * @param tag the tag to retrieve. * @param index which element of the array of data for this tag to retrieve. * @return the data for the tag. */ public Object getValue(String tag, int index) { TagGetter get = MapHolder.getterMap.get(getTagType(tag)); return get != null ? get.get(this, tag, index) : ""; } /** * Gets data for a tag from this list. * * @param tag the tag to retrieve. * @param index which element of the array of data for this tag to retrieve. * @return the data for the tag. */ public Object getValue(Tag tag, int index) { return getValue(tag.getId(), index); } /** * Gets a string tag from this list. * * @param tag the tag to retrieve. * @param index which element of the array of data for this tag to retrieve. * @return the data for the tag. */ @Override public String getString(String tag, int index) { return getValue(tag, index).toString(); } /** * Gets a string tag from this list. * * @param tag the tag to retrieve. * @param index which element of the array of data for this tag to retrieve. * @return the data for the tag. */ public String getString(Tag tag, int index) { return getString(tag.getId(), index); } /** * Gets a numeric tag from this list. * * @param tag the tag to retrieve. * @param index which element of the array of data for this tag to retrieve. * @return the data for the tag. */ public Number getNumber(String tag, int index) { Object data = getValue(tag, index); if (!(data instanceof Number)) { throw new IllegalArgumentException("Tag [" + tag + "] is not a number"); } return (Number) data; } /** * Gets a numeric tag from this list. * * @param tag the tag to retrieve. * @param index which element of the array of data for this tag to retrieve. * @return the data for the tag. */ public Number getNumber(Tag tag, int index) { return getNumber(tag.getId(), index); } /** * Gets a list of all the tags contained in this list. * * @return a list of tag names. */ public List<String> getTagNames() { final List<String> list = new LinkedList<String>(); gst.gst_tag_list_foreach(this, new GstTagListAPI.TagForeachFunc() { public void callback(Pointer ptr, String tag, Pointer user_data) { list.add(tag); } }, null); return list; } /** * Merges this tag list and {@code list2} into a new list. * If {@code list2} is null, a copy of this list is returned. * * @param list2 the other tag list to merge with this one. * @param mode the {@link TagMergeMode}. * @return a new tag list. */ public TagList merge(TagList list2, TagMergeMode mode) { return gst.gst_tag_list_merge(this, list2, mode); } /** * Gets the low level type for the tag. * * @param tag the tag * @return the type of {@code tag} */ private static GType getTagType(String tag) { GType type = MapHolder.tagTypeMap.get(tag); if (type != null) { return type; } MapHolder.tagTypeMap.put(tag, type = gst.gst_tag_get_type(tag)); return type; } @Override protected void disposeNativeHandle(Pointer ptr) { gst.gst_tag_list_free(ptr); } private static interface TagGetter { Object get(TagList tl, String tag, int index); } // // Put the maps in a holder class so they don't get initialized until used. // This helps avoid calling gstreamer methods before Gst.init(). // private static final class MapHolder { private static final Map<GType, TagGetter> getterMap = new HashMap<GType, TagGetter>() {{ put(GType.INT, new TagGetter() { public Object get(TagList tl, String tag, int index) { int[] value = { 0 }; gst.gst_tag_list_get_int_index(tl, tag, index, value); return value[0]; } }); put(GType.UINT, new TagGetter() { public Object get(TagList tl, String tag, int index) { int[] value = { 0 }; gst.gst_tag_list_get_uint_index(tl, tag, index, value); return value[0]; } }); put(GType.INT64, new TagGetter() { public Object get(TagList tl, String tag, int index) { long[] value = { 0 }; gst.gst_tag_list_get_int64_index(tl, tag, index, value); return value[0]; } }); put(GType.DOUBLE, new TagGetter() { public Object get(TagList tl, String tag, int index) { double[] value = { 0d }; gst.gst_tag_list_get_double_index(tl, tag, index, value); return value[0]; } }); put(GType.STRING, new TagGetter() { public Object get(TagList tl, String tag, int index) { Pointer[] value = { null }; gst.gst_tag_list_get_string_index(tl, tag, index, value); if (value[0] == null) { return null; } @SuppressWarnings("deprecation") String ret = value[0].getString(0, false); GLIB_API.g_free(value[0]); return ret; } }); put(GDate.GTYPE, new TagGetter() { public Object get(TagList tl, String tag, int index) { PointerByReference value = new PointerByReference(); gst.gst_tag_list_get_date_index(tl, tag, index, value); if (value.getValue() == null) { return null; } return new GDate(value.getValue(), false, true); } }); }}; static private final Map<String, GType> tagTypeMap = new ConcurrentHashMap<String, GType>(); } }