Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated audio outputs to conform to the AES57-2011 spec #357

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -666,16 +666,15 @@ private DefaultMutableTreeNode aesToNode (AESAudioMetadata aes)
region.add (timeline);
int nchan = aes.getNumChannels ();
if (nchan != AESAudioMetadata.NULL) {
String[] locs = aes.getMapLocations ();
region.add (new DefaultMutableTreeNode
("NumChannels: " + Integer.toString (nchan), false));
for (String loc : locs) {
for (int ch = 0; ch < nchan; ch++) {
// write a stream element for each channel
DefaultMutableTreeNode stream =
new DefaultMutableTreeNode ("Stream", true);
region.add (stream);
stream.add (new DefaultMutableTreeNode
("ChannelAssignment: " + loc, false));
("ChannelNum: " + Integer.toString (ch), false));
}
}
face.add (region);
Expand Down Expand Up @@ -745,95 +744,34 @@ private void addAESTimeRange (DefaultMutableTreeNode parent,
AESAudioMetadata.TimeDesc start,
AESAudioMetadata.TimeDesc duration)
{
// Put the start time in
DefaultMutableTreeNode node =
new DefaultMutableTreeNode ("Start", true);
// Put in boilerplate to match the AES schema
node.add (new DefaultMutableTreeNode
("FrameCount: 30", false));
node.add (new DefaultMutableTreeNode
("TimeBase: 1000"));
node.add (new DefaultMutableTreeNode
("VideoField: FIELD_1"));
node.add (new DefaultMutableTreeNode
("CountingMode: NTSC_NON_DROP_FRAME", false));
node.add (new DefaultMutableTreeNode
("Hours: " + start.getHours(), false));
node.add (new DefaultMutableTreeNode
("Minutes: " + start.getMinutes(), false));
node.add (new DefaultMutableTreeNode
("Seconds: " + start.getSeconds(), false));
node.add (new DefaultMutableTreeNode
("Frames: " + start.getFrames(), false));

// Do samples a bit more elaborately than is really necessary,
// to maintain parallelism with the xml schema.
DefaultMutableTreeNode snode = new DefaultMutableTreeNode ("Samples",
true);
double sr = start.getSampleRate ();
if (sr == 1.0) {
sr = _sampleRate;
}
snode.add (new DefaultMutableTreeNode ("SampleRate: S" +
Integer.toString ((int) sr),
false));
snode.add (new DefaultMutableTreeNode ("NumberOfSamples: " +
start.getSamples (), false ));
node.add (snode);

snode = new DefaultMutableTreeNode ("FilmFraming", true);
snode.add (new DefaultMutableTreeNode ("Framing: NOT_APPLICABLE",
false));
snode.add (new DefaultMutableTreeNode ("Type: ntscFilmFramingType",
false));
node.add (snode);
parent.add (node);
writeAESTimeRangePart(parent, "StartTime", start);

// Duration is optional.
if (duration != null) {
node = new DefaultMutableTreeNode ("Duration", true);
// Put in boilerplate to match the AES schema
node.add (new DefaultMutableTreeNode
("FrameCount: 30", false));
node.add (new DefaultMutableTreeNode
("TimeBase: 1000"));
node.add (new DefaultMutableTreeNode
("VideoField: FIELD_1"));
node.add (new DefaultMutableTreeNode
("CountingMode: NTSC_NON_DROP_FRAME", false));
node.add (new DefaultMutableTreeNode
("Hours: " + duration.getHours(), false));
node.add (new DefaultMutableTreeNode
("Minutes: " + duration.getMinutes(), false));
node.add (new DefaultMutableTreeNode
("Seconds: " + duration.getSeconds(), false));
node.add (new DefaultMutableTreeNode
("Frames: " + duration.getFrames(), false));

// Do samples a bit more elaborately than is really necessary,
// to maintain parallelism with the xml schema.
snode = new DefaultMutableTreeNode ("Samples", true);
sr = duration.getSampleRate ();
if (sr == 1.0) {
sr = _sampleRate;
}
snode.add (new DefaultMutableTreeNode ("SamplesRate S" +
Integer.toString ((int) sr),
false));
snode.add (new DefaultMutableTreeNode ("NumberOfSamples: " +
duration.getSamples (),
false ));
node.add (snode);

snode = new DefaultMutableTreeNode ("FilmFraming", true);
snode.add (new DefaultMutableTreeNode ("Framing: NOT_APPLICABLE",
false));
snode.add (new DefaultMutableTreeNode ("Type: ntscFilmFramingType",
false));
node.add (snode);
parent.add (node);
writeAESTimeRangePart(parent, "Duration", duration);
}
}

private void writeAESTimeRangePart(DefaultMutableTreeNode parent,
String name, AESAudioMetadata.TimeDesc timeDesc) {
double sampleRate = timeDesc.getSampleRate ();
if (sampleRate == 1.0) {
sampleRate = _sampleRate;
}

DefaultMutableTreeNode node =
new DefaultMutableTreeNode (name, true);
node.add(new DefaultMutableTreeNode(
"Value: " + String.valueOf(timeDesc.getSamples()), false));
node.add(new DefaultMutableTreeNode(
"EditRate: " + sampleRate, false));
node.add(new DefaultMutableTreeNode(
"FactorNumerator: 1", false));
node.add(new DefaultMutableTreeNode(
"FactorDenominator: 1", false));

parent.add (node);
}

/* Function for turning the textMD metadata into a subtree. */
private DefaultMutableTreeNode textMDToNode (TextMDMetadata textMD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class AESAudioMetadata
******************************************************************/

/** Constant value for the SchemaVersion field */
public static final String SCHEMA_VERSION = "1.02b";
public static final String SCHEMA_VERSION = "1.0.0";

/** Constant value for the disposition field */
private static final String DEFAULT_DISPOSITION = "validation";
Expand Down Expand Up @@ -160,20 +160,9 @@ public void setBitrateReduction (String codecName,
* accessed through the public methods of this interface.
*/
public static interface TimeDesc {
/** Returns the hours component. */
public long getHours ();
/** Returns the minutes component. */
public long getMinutes ();
/** Returns the seconds component. */
public long getSeconds ();
/** Returns the frames component of the fraction of a second.
* We always consider frames to be thirtieths of a second. */
public long getFrames ();
/** Returns the samples remaining after the frames part of
* the fractional second. */
/** Returns the number of samples. */
public long getSamples ();
/** Returns the sample rate on which the samples remainder
* is based. */
/** Returns the sample rate. */
public double getSampleRate ();
}

Expand Down Expand Up @@ -371,26 +360,12 @@ public void setWordSize (int wordSize)
*/
class TimeDescImpl implements TimeDesc
{
private long _hours;
private long _minutes;
private long _seconds;
private long _frames;
private long _samples;
private double _sampleRate;
private long _frameCount;

/* Constructor rewritten to avoid rounding errors when converting to
* TCF. Now uses integer remainder math instead of floating point.
* Changed the base unit from a double representing seconds to a long
* representing samples. Changed all existing calls (that I could find)
* to this method to accomodate this change.
*
* @author David Ackerman
*/

public TimeDescImpl (long samples)
{
long _sample_count = samples;
_frameCount = 30;
_samples = samples;
_sampleRate = _curFormatRegion.getSampleRate ();

/* It seems that this method is initially called before a valid
Expand All @@ -400,73 +375,15 @@ public TimeDescImpl (long samples)
if (_sampleRate < 0) {
_sampleRate = 44100.0; //reasonable default value
}

long sample_in_1_frame = (long)(_sampleRate/_frameCount);
long sample_in_1_second = sample_in_1_frame * _frameCount;
long sample_in_1_minute = sample_in_1_frame * _frameCount * 60;
long sample_in_1_hour = sample_in_1_frame * _frameCount * 60 * 60;
long sample_in_1_day = sample_in_1_frame * _frameCount * 60 * 60 * 24;

// BWF allows for a negative timestamp but tcf does not, so adjust
// time accordingly
// this might be a good place to report a warning during validation
if (_sample_count < 0) {
_sample_count += sample_in_1_day;
_sample_count = (_sample_count % sample_in_1_day);
}

_hours = _sample_count / sample_in_1_hour;
_sample_count -= _hours * sample_in_1_hour;
_minutes = _sample_count / sample_in_1_minute;
_sample_count -= _minutes * sample_in_1_minute;
_seconds = _sample_count / sample_in_1_second;
_sample_count -= _seconds * sample_in_1_second;
_frames = _sample_count / sample_in_1_frame;
_sample_count -= _frames * sample_in_1_frame;
_samples = _sample_count;

/* At present TCF does not have the ability to handle time stamps
* > midnight. Industry practice is to roll the clock forward to
* zero or back to 23:59:59:29... when crossing this boundary
* condition.
*/
_hours = _hours % 24;
}

/** Returns the hours component. */
@Override
public long getHours () {
return _hours;
}

/** Returns the minutes component. */
@Override
public long getMinutes () {
return _minutes;
}

/** Returns the seconds component. */
@Override
public long getSeconds () {
return _seconds;
}

/** Returns the frames component of the fraction of a second.
* We always consider frames to be thirtieths of a second. */
@Override
public long getFrames () {
return _frames;
}

/** Returns the samples remaining after the frames part of
* the fractional second. */
/** Returns the number of samples. */
@Override
public long getSamples () {
return _samples;
}

/** Returns the sample rate on which the samples remainder
* is based. */
/** Returns the sample rate. */
@Override
public double getSampleRate () {
return _sampleRate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package edu.harvard.hul.ois.jhove.handler;

import edu.harvard.hul.ois.jhove.*;

import java.text.*;
import java.util.*;

Expand Down Expand Up @@ -994,17 +995,22 @@ private void showAESAudioMetadata (AESAudioMetadata aes, String margin,
if (startTime != null) {
writeAESTimeRange (margn3, startTime, f.getDuration());
}

// For the present, assume just one face region
AESAudioMetadata.FaceRegion facergn = f.getFaceRegion(0);
_writer.println(margn3 + "Region: ");
_writer.println (margn4 + "TimeRange: ");
writeAESTimeRange(margn4, facergn.getStartTime(), facergn.getDuration());

int nchan = aes.getNumChannels ();
if (nchan != AESAudioMetadata.NULL) {
_writer.println (margn4 + "NumChannels: " +
Integer.toString (nchan));
}
String[] locs = aes.getMapLocations ();
for (int ch = 0; ch < nchan; ch++) {
// write a stream description for each channel
_writer.println (margn4 + "Stream:");
_writer.println (margn5 + "ChannelNum: " + Integer.toString (ch));
_writer.println (margn5 + "ChannelAssignment: " + locs[ch]);
}
}

Expand Down Expand Up @@ -1062,62 +1068,29 @@ private void writeAESTimeRange (String baseIndent,
AESAudioMetadata.TimeDesc start,
AESAudioMetadata.TimeDesc duration)
{
final String margn1 = baseIndent + " ";
final String margn2 = margn1 + " ";
final String margn3 = margn2 + " ";
_writer.println (margn1 + "StartTime:");
_writer.println (margn2 + "FrameCount: 30");
_writer.println (margn2 + "TimeBase: 1000");
_writer.println (margn2 + "VideoField: FIELD_1");
_writer.println (margn2 + "CountingMode: NTSC_NON_DROP_FRAME");
_writer.println (margn2 + "Hours: " +
Long.toString (start.getHours ()));
_writer.println (margn2 + "Minutes: " +
Long.toString (start.getMinutes ()));
_writer.println (margn2 + "Seconds: " +
Long.toString (start.getSeconds ()));
_writer.println (margn2 + "Frames: " +
Long.toString (start.getFrames ()));
_writer.println (margn2 + "Samples: ");
double sr = start.getSampleRate ();
if (sr == 1.0) {
sr = _sampleRate;
}
_writer.println (margn3 + "SampleRate: S" +
Integer.toString ((int) sr));
_writer.println (margn3 + "NumberOfSamples: " +
Long.toString (start.getSamples ()));
_writer.println (margn2 + "FilmFraming: NOT_APPLICABLE");
_writer.println (margn3 + "Type: ntscFilmFramingType");

writeAESTimeRangePart(baseIndent, "StartTime", start);

if (duration != null) {
_writer.println (margn1 + "Duration:");
_writer.println (margn2 + "FrameCount: 30");
_writer.println (margn2 + "TimeBase: 1000");
_writer.println (margn2 + "VideoField: FIELD_1");
_writer.println (margn2 + "CountingMode: NTSC_NON_DROP_FRAME");
_writer.println (margn2 + "Hours: " +
Long.toString (duration.getHours ()));
_writer.println (margn2 + "Minutes: " +
Long.toString (duration.getMinutes ()));
_writer.println (margn2 + "Seconds: " +
Long.toString (duration.getSeconds ()));
_writer.println (margn2 + "Frames: " +
Long.toString (duration.getFrames ()));
_writer.println (margn2 + "Samples: ");
sr = duration.getSampleRate ();
if (sr == 1.0) {
sr = _sampleRate;
}
_writer.println (margn3 + "SampleRate: S" +
Integer.toString ((int) sr));
_writer.println (margn3 + "NumberOfSamples: " +
Long.toString (duration.getSamples ()));
_writer.println (margn2 + "FilmFraming: NOT_APPLICABLE");
_writer.println (margn3 + "Type: ntscFilmFramingType");
writeAESTimeRangePart(baseIndent, "Duration", duration);
}
}

private void writeAESTimeRangePart(String baseIndent, String name, AESAudioMetadata.TimeDesc timeDesc) {
String margn1 = baseIndent + " ";
String margn2 = margn1 + " ";

_writer.println (margn1 + name + ": ");

double sampleRate = timeDesc.getSampleRate();
if (sampleRate == 1.0) {
sampleRate = _sampleRate;
}

_writer.println (margn2 + "Value: " + String.valueOf(timeDesc.getSamples()));
_writer.println (margn2 + "EditRate: " + Integer.toString ((int) sampleRate));
_writer.println (margn2 + "FactorNumerator: 1");
_writer.println (margn2 + "FactorDenominator: 1");
}

/**
* Display the NISO image metadata formatted according to
Expand Down
Loading