/* * @(#)AmigaVideoFormatKeys.java * * Copyright (c) 2011 Werner Randelshofer, Goldau, Switzerland. * All rights reserved. * * You may not use, copy or modify this file, except in compliance onlyWith the * license agreement you entered into onlyWith Werner Randelshofer. * For details see accompanying license terms. */ package org.monte.media.anim; import org.monte.media.Format; import org.monte.media.FormatKey; import org.monte.media.VideoFormatKeys; import org.monte.media.math.Rational; import java.util.ArrayList; import java.util.Iterator; /** * {@code AmigaVideoFormatKeys}. * * @author Werner Randelshofer * @version $Id$ */ public class AmigaVideoFormatKeys extends VideoFormatKeys { /** The Amiga monitor id. */ public final static FormatKey<Integer> MonitorIdKey = new FormatKey<Integer>("monitorId", Integer.class); /** Anim Op5 . */ public static final String ENCODING_ANIM_OP5 = "op5"; enum ColorMode { HAM, EHB, NORMAL } public final static FormatKey<ColorMode> ColorModeKey = new FormatKey<ColorMode>("colorMode", ColorMode.class); public static Format fromCAMG(int camg) { AmigaDisplayInfo i = AmigaDisplayInfo.getInfo(camg); return new Format( MediaTypeKey, MediaType.VIDEO, EncodingKey, ENCODING_BITMAP_IMAGE, WidthKey, i.textOverscanWidth, HeightKey, i.textOverscanHeight, MonitorIdKey, camg & AmigaDisplayInfo.MONITOR_ID_MASK, ColorModeKey, i.isEHB() ? ColorMode.EHB : (i.isHAM() ? ColorMode.HAM : ColorMode.NORMAL), InterlaceKey, i.isInterlace(), PixelAspectRatioKey, new Rational(i.resolutionX, i.resolutionY), FrameRateKey, new Rational(i.fps, 1)); } public static int toCAMG(Format fmt) { int camg = 0; // determine monitor id int monitorId = 0; if (fmt.containsKey(MonitorIdKey)) { monitorId = fmt.get(MonitorIdKey); } else { ArrayList<AmigaDisplayInfo> infs = new ArrayList<AmigaDisplayInfo>(AmigaDisplayInfo.getAllInfos().values()); if (fmt.containsKey(InterlaceKey)) { boolean value = fmt.get(InterlaceKey); reduceListBoolean(value, new InfGetter<Boolean>() { @Override public Boolean get(AmigaDisplayInfo inf) { return inf.isInterlace(); } }, infs); } if (fmt.containsKey(FrameRateKey)) { Rational value = fmt.get(FrameRateKey); reduceListRational(value, new InfGetter<Rational>() { @Override public Rational get(AmigaDisplayInfo inf) { return new Rational(inf.fps, 1); } }, infs); } if (fmt.containsKey(PixelAspectRatioKey)) { Rational value = fmt.get(PixelAspectRatioKey); reduceListRational(value, new InfGetter<Rational>() { @Override public Rational get(AmigaDisplayInfo inf) { return new Rational(inf.resolutionX, inf.resolutionY); } }, infs); } ArrayList<AmigaDisplayInfo> bestInfs = new ArrayList<AmigaDisplayInfo>(infs); if (fmt.containsKey(WidthKey)) { int value = fmt.get(WidthKey); reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() { @Override public Integer get(AmigaDisplayInfo inf) { return inf.textOverscanWidth; } }, infs); } if (fmt.containsKey(HeightKey)) { Integer value = fmt.get(HeightKey); reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() { @Override public Integer get(AmigaDisplayInfo inf) { return inf.textOverscanHeight; } }, infs); } if (infs.isEmpty()) { infs = new ArrayList<AmigaDisplayInfo>(bestInfs); if (fmt.containsKey(WidthKey)) { Integer value = fmt.get(WidthKey); reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() { @Override public Integer get(AmigaDisplayInfo inf) { return inf.maxOverscanWidth; } }, infs); } if (fmt.containsKey(HeightKey)) { Integer value = fmt.get(HeightKey); reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() { @Override public Integer get(AmigaDisplayInfo inf) { return inf.maxOverscanHeight; } }, infs); } } if (infs.isEmpty()) { infs = new ArrayList<AmigaDisplayInfo>(bestInfs); if (fmt.containsKey(WidthKey)) { Integer value = fmt.get(WidthKey); reduceListInteger(value, new InfGetter<Integer>() { @Override public Integer get(AmigaDisplayInfo inf) { return inf.maxOverscanWidth; } }, infs); } if (fmt.containsKey(HeightKey)) { Integer value = fmt.get(HeightKey); reduceListInteger(value, new InfGetter<Integer>() { @Override public Integer get(AmigaDisplayInfo inf) { return inf.maxOverscanHeight; } }, infs); } } } int colorMode=0; if (fmt.containsKey(ColorModeKey)) { switch (fmt.get(ColorModeKey)) { case EHB: colorMode=AmigaDisplayInfo.EHB_COLORMODE; break; case HAM: colorMode=AmigaDisplayInfo.HAM_COLORMODE; break; case NORMAL: break; } } camg = monitorId|colorMode; return camg; } private interface InfGetter<T> { public T get(AmigaDisplayInfo inf); } private static void reduceListRational(Rational value, InfGetter<Rational> g, ArrayList<AmigaDisplayInfo> infs) { ArrayList<AmigaDisplayInfo> bestInfs = new ArrayList<AmigaDisplayInfo>(); bestInfs.add(infs.get(0)); float bestCost = g.get(infs.get(0)).subtract(value).floatValue(); bestCost *= bestCost; for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) { AmigaDisplayInfo inf = i.next(); Rational iv = g.get(inf); if (iv.compareTo(value) != 0) { i.remove(); } float icost = iv.subtract(value).floatValue(); icost *= icost; if (icost < bestCost) { bestInfs.clear(); bestCost = icost; } else if (icost == bestCost) { bestInfs.add(inf); } } if (infs.isEmpty()) { infs.addAll(bestInfs); } } private static void reduceListInteger(int value, InfGetter<Integer> g, ArrayList<AmigaDisplayInfo> infs) { ArrayList<AmigaDisplayInfo> bestInfs = new ArrayList<AmigaDisplayInfo>(); bestInfs.add(infs.get(0)); float bestCost = g.get(infs.get(0)) - value; bestCost *= bestCost; for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) { AmigaDisplayInfo inf = i.next(); int iv = g.get(inf); if (iv != value) { i.remove(); } float icost = iv - value; icost *= icost; if (icost < bestCost) { bestInfs.clear(); bestCost = icost; } else if (icost == bestCost) { bestInfs.add(inf); } } if (infs.isEmpty()) { infs.addAll(bestInfs); } } private static void reduceListIntegerOnlyTakeIfSmaller(int value, InfGetter<Integer> g, ArrayList<AmigaDisplayInfo> infs) { reduceListInteger(value, g, infs); for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) { AmigaDisplayInfo inf = i.next(); int iv = g.get(inf); if (value > iv) { i.remove(); } } } private static void reduceListBoolean(boolean value, InfGetter<Boolean> g, ArrayList<AmigaDisplayInfo> infs) { for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) { AmigaDisplayInfo inf = i.next(); boolean iv = g.get(inf); if (iv != value) { i.remove(); } } } }