@@ -81,16 +81,26 @@ public class StreamingWriter {
8181
8282 private abstract class ContainerWriter extends OutputStream {
8383
84+ enum State {
85+ READY ,
86+ WRITING
87+ }
88+
8489 private final long bodySID ;
8590 private final long indexSID ;
8691 private long bytesToWrite ;
8792 private long ecOffset = 0 ;
93+ private State state = State .READY ;
8894
8995 ContainerWriter (long bodySID , long indexSID ) {
9096 this .bodySID = bodySID ;
9197 this .indexSID = indexSID ;
9298 }
9399
100+ State getState () {
101+ return this .state ;
102+ }
103+
94104 long getIndexSID () {
95105 return this .indexSID ;
96106 }
@@ -103,16 +113,16 @@ boolean isActive() {
103113 return StreamingWriter .this .currentContainer == this ;
104114 }
105115
106- long getBytesToWrite () {
107- return bytesToWrite ;
116+ boolean isWriting () {
117+ return this . state . equals ( State . WRITING ) ;
108118 }
109119
110- /*
111- * TODO: this is super ugly as it interferes with the ability of the GC to write
112- * stuff to itself
113- */
114- void setBytesToWrite (long bytesToWrite ) {
120+ void startWriting (long bytesToWrite ) {
121+ if (this .state != State .READY ) {
122+ throw new IllegalStateException ("ContainerWriter is not in READY state" );
123+ }
115124 this .bytesToWrite = bytesToWrite ;
125+ this .state = State .WRITING ;
116126 }
117127
118128 abstract byte [] drainIndexSegments () throws IOException , MXFException ;
@@ -136,25 +146,39 @@ public void write(int b) throws IOException {
136146 if (!this .isActive ()) {
137147 throw new IllegalStateException ("ContainerWriter is not active" );
138148 }
149+ if (this .state != State .WRITING ) {
150+ throw new IllegalStateException ("ContainerWriter is not in WRITING state" );
151+ }
139152 if (this .bytesToWrite - 1 < 0 )
140153 throw new EOFException ("Attempting to write more bytes than allocated to the container" );
141154 StreamingWriter .this .fos .write (b );
142155 this .bytesToWrite --;
143156 this .ecOffset ++;
157+
158+ if (this .bytesToWrite == 0 ) {
159+ this .state = State .READY ;
160+ }
144161 }
145162
146163 @ Override
147164 public void write (byte [] b , int off , int len ) throws IOException {
148165 if (!this .isActive ()) {
149166 throw new IllegalStateException ("ContainerWriter is not active" );
150167 }
168+ if (this .state != State .WRITING ) {
169+ throw new IllegalStateException ("ContainerWriter is not in WRITING state" );
170+ }
151171 if (this .bytesToWrite - len < 0 ) {
152172 throw new EOFException ("Attempting to write more bytes than allocated to the container" );
153173 }
154174
155175 StreamingWriter .this .fos .write (b , off , len );
156176 this .bytesToWrite -= len ;
157177 this .ecOffset += len ;
178+
179+ if (this .bytesToWrite == 0 ) {
180+ this .state = State .READY ;
181+ }
158182 }
159183
160184 @ Override
@@ -165,13 +189,14 @@ public void close() throws IOException {
165189 */
166190 }
167191
168- static byte [] serializeIndexTableSegment (IndexTableSegment its , EventHandler evthandler ) throws IOException , MXFException {
192+ static byte [] serializeIndexTableSegment (IndexTableSegment its , EventHandler evthandler )
193+ throws IOException , MXFException {
169194 /* serialize the index table segment */
170195
171196 /*
172- * The AtomicReference is necessary since the variable is initialized in the
173- * inline MXFOutputContext
174- */
197+ * The AtomicReference is necessary since the variable is initialized in the
198+ * inline MXFOutputContext
199+ */
175200 AtomicReference <Set > ars = new AtomicReference <>();
176201 MXFOutputContext ctx = new MXFOutputContext () {
177202
@@ -234,15 +259,9 @@ public AUID getAUID(long localtag) {
234259 */
235260 class GCClipCBEWriter extends ContainerWriter {
236261
237- enum State {
238- READY ,
239- WRITTEN ,
240- DRAINED
241- }
242-
243262 private long accessUnitSize ;
244263 private long accessUnitCount ;
245- private State state = State . READY ;
264+ private boolean indexTableFilled = false ;
246265
247266 public GCClipCBEWriter (long bodySID , long indexSID ) {
248267 super (bodySID , indexSID );
@@ -257,7 +276,9 @@ public GCClipCBEWriter(long bodySID, long indexSID) {
257276 * @throws IOException If an I/O error occurs.
258277 */
259278 public void nextClip (UL elementKey , long accessUnitSize , long accessUnitCount ) throws IOException {
260- Objects .requireNonNull (elementKey , "Element Key cannot be null" );
279+ if (elementKey == null ) {
280+ throw new IllegalArgumentException ("Element Key cannot be null" );
281+ }
261282
262283 if (accessUnitCount < 0 ) {
263284 throw new IllegalArgumentException ("Access Unit Count cannot be negative" );
@@ -271,20 +292,19 @@ public void nextClip(UL elementKey, long accessUnitSize, long accessUnitCount) t
271292 throw new IllegalStateException ("ContainerWriter is not active" );
272293 }
273294
274- if (this .state != State .READY ) {
295+ if (this .getState () != State .READY ) {
275296 throw new IllegalStateException ("ContainerWriter is not ready for the next clip" );
276297 }
277298
278299 long clipSize = accessUnitCount * accessUnitSize ;
279300
280301 StreamingWriter .this .fos .writeUL (elementKey );
281302 StreamingWriter .this .fos .writeBERLength (clipSize );
282- this .setBytesToWrite (clipSize );
303+ this .startWriting (clipSize );
283304
284305 this .accessUnitCount = accessUnitCount ;
285306 this .accessUnitSize = accessUnitSize ;
286-
287- this .state = State .WRITTEN ;
307+ this .indexTableFilled = true ;
288308 }
289309
290310 @ Override
@@ -294,10 +314,10 @@ long getDuration() {
294314
295315 @ Override
296316 byte [] drainIndexSegments () throws IOException , MXFException {
297- if (this .state != State . WRITTEN ) {
317+ if (! this .indexTableFilled ) {
298318 return null ;
299319 }
300- this .state = State . DRAINED ;
320+ this .indexTableFilled = false ;
301321
302322 var its = new IndexTableSegment ();
303323 its .InstanceID = StreamingWriter .this .uidGenerator .generate (this );
@@ -345,7 +365,7 @@ public void nextElement(UL elementKey, long elementLength) throws IOException {
345365 }
346366 StreamingWriter .this .fos .writeUL (elementKey );
347367 StreamingWriter .this .fos .writeBERLength (elementLength );
348- this .setBytesToWrite (elementLength );
368+ this .startWriting (elementLength );
349369 }
350370
351371 @ Override
@@ -420,17 +440,16 @@ public void nextClip(UL elementKey, long clipSize) throws IOException {
420440 * EXCEPTION: ASDCPLib incorrectly includes the Clip KL in the essence container
421441 * offset for IAB files
422442 */
423- this .setBytesToWrite (50 );
424- MXFDataOutput mos = new MXFDataOutput (this );
425- mos .writeUL (elementKey );
426- mos .writeBERLength (clipSize );
427- mos .flush ();
443+ long curPos = StreamingWriter .this .fos .getWrittenCount ();
444+ StreamingWriter .this .fos .writeUL (elementKey );
445+ StreamingWriter .this .fos .writeBERLength (clipSize );
446+ this .setPosition (this .getPosition () + StreamingWriter .this .fos .getWrittenCount () - curPos );
428447 } else {
429448 StreamingWriter .this .fos .writeUL (elementKey );
430449 StreamingWriter .this .fos .writeBERLength (clipSize );
431450 }
432451
433- this .setBytesToWrite (clipSize );
452+ this .startWriting (clipSize );
434453
435454 this .state = State .WRITTEN ;
436455 }
@@ -567,7 +586,7 @@ public void nextElement(UL elementKey, long elementSize) throws IOException {
567586 StreamingWriter .this .fos .writeBERLength (elementSize );
568587 this .setPosition (this .getPosition () + StreamingWriter .this .fos .getWrittenCount () - curPos );
569588
570- this .setBytesToWrite (elementSize );
589+ this .startWriting (elementSize );
571590 }
572591
573592 @ Override
@@ -667,7 +686,8 @@ private enum State {
667686 private final UIDGenerator uidGenerator ;
668687
669688 /**
670- * Instantiates a StreamingWriter. The StreamingWriter makes a copy of the provided preface.
689+ * Instantiates a StreamingWriter. The StreamingWriter makes a copy of the
690+ * provided preface.
671691 *
672692 * @param os Output stream to write the MXF file to.
673693 * @param preface Preface set of the MXF file.
@@ -682,7 +702,8 @@ public StreamingWriter(OutputStream os, Preface preface, EventHandler evthandler
682702 }
683703
684704 /**
685- * Instantiates a StreamingWriter with a custom UID generator. The StreamingWriter makes a copy of the provided preface.
705+ * Instantiates a StreamingWriter with a custom UID generator. The
706+ * StreamingWriter makes a copy of the provided preface.
686707 *
687708 * @param os Output stream to write the MXF file to.
688709 * @param preface Preface set of the MXF file.
@@ -861,9 +882,8 @@ private void closeCurrentPartition() throws IOException, KLVException, MXFExcept
861882 }
862883
863884 /* are we done with the current partition? */
864- /* TODO: replace with state check */
865- if (this .currentContainer .getBytesToWrite () != 0 ) {
866- throw new RuntimeException ();
885+ if (this .currentContainer .isWriting ()) {
886+ throw new IllegalStateException ("The current partition cannot be closed because it is still writing" );
867887 }
868888 /* do we need to create an index partition for the current essence container */
869889 if (this .currentContainer .getIndexSID () != 0 ) {
0 commit comments