• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.cts;
18 
19 import java.io.IOException;
20 import java.io.RandomAccessFile;
21 
22 /**
23  * Writes an IVF file.
24  *
25  * IVF format is a simple container format for VP8 encoded frames defined at
26  * http://wiki.multimedia.cx/index.php?title=IVF.
27  */
28 
29 public class IvfWriter {
30     private static final byte HEADER_END = 32;
31     private RandomAccessFile mOutputFile;
32     private int mWidth;
33     private int mHeight;
34     private int mScale;
35     private int mRate;
36     private int mFrameCount;
37 
38     /**
39      * Initializes the IVF file writer.
40      *
41      * Timebase fraction is in format scale/rate, e.g. 1/1000
42      * Timestamp values supplied while writing frames should be in accordance
43      * with this timebase value.
44      *
45      * @param filename   name of the IVF file
46      * @param width      frame width
47      * @param height     frame height
48      * @param scale      timebase scale (or numerator of the timebase fraction)
49      * @param rate       timebase rate (or denominator of the timebase fraction)
50      */
IvfWriter(String filename, int width, int height, int scale, int rate)51     public IvfWriter(String filename,
52                      int width, int height,
53                      int scale, int rate) throws IOException {
54         mOutputFile = new RandomAccessFile(filename, "rw");
55         mWidth = width;
56         mHeight = height;
57         mScale = scale;
58         mRate = rate;
59         mFrameCount = 0;
60         mOutputFile.setLength(0);
61         mOutputFile.seek(HEADER_END);  // Skip the header for now, as framecount is unknown
62     }
63 
64     /**
65      * Initializes the IVF file writer with a microsecond timebase.
66      *
67      * Microsecond timebase is default for OMX thus stagefright.
68      *
69      * @param filename   name of the IVF file
70      * @param width      frame width
71      * @param height     frame height
72      */
IvfWriter(String filename, int width, int height)73     public IvfWriter(String filename, int width, int height) throws IOException {
74         this(filename, width, height, 1, 1000000);
75     }
76 
77     /**
78      * Finalizes the IVF header and closes the file.
79      */
close()80     public void close() throws IOException{
81         // Write header now
82         mOutputFile.seek(0);
83         mOutputFile.write(makeIvfHeader(mFrameCount, mWidth, mHeight, mScale, mRate));
84         mOutputFile.close();
85     }
86 
87     /**
88      * Writes a single encoded VP8 frame with its frame header.
89      *
90      * @param frame     actual contents of the encoded frame data
91      * @param timeStamp timestamp of the frame (in accordance to specified timebase)
92      */
writeFrame(byte[] frame, long timeStamp)93     public void writeFrame(byte[] frame, long timeStamp) throws IOException {
94         mOutputFile.write(makeIvfFrameHeader(frame.length, timeStamp));
95         mOutputFile.write(frame);
96         mFrameCount++;
97     }
98 
99     /**
100      * Makes a 32 byte file header for IVF format.
101      *
102      * Timebase fraction is in format scale/rate, e.g. 1/1000
103      *
104      * @param frameCount total number of frames file contains
105      * @param width      frame width
106      * @param height     frame height
107      * @param scale      timebase scale (or numerator of the timebase fraction)
108      * @param rate       timebase rate (or denominator of the timebase fraction)
109      */
makeIvfHeader(int frameCount, int width, int height, int scale, int rate)110     private static byte[] makeIvfHeader(int frameCount, int width, int height, int scale, int rate){
111         byte[] ivfHeader = new byte[32];
112         ivfHeader[0] = 'D';
113         ivfHeader[1] = 'K';
114         ivfHeader[2] = 'I';
115         ivfHeader[3] = 'F';
116         lay16Bits(ivfHeader, 4, 0);  // version
117         lay16Bits(ivfHeader, 6, 32);  // header size
118         ivfHeader[8] = 'V';  // fourcc
119         ivfHeader[9] = 'P';
120         ivfHeader[10] = '8';
121         ivfHeader[11] = '0';
122         lay16Bits(ivfHeader, 12, width);
123         lay16Bits(ivfHeader, 14, height);
124         lay32Bits(ivfHeader, 16, rate);  // scale/rate
125         lay32Bits(ivfHeader, 20, scale);
126         lay32Bits(ivfHeader, 24, frameCount);
127         lay32Bits(ivfHeader, 28, 0);  // unused
128         return ivfHeader;
129     }
130 
131     /**
132      * Makes a 12 byte header for an encoded frame.
133      *
134      * @param size      frame size
135      * @param timestamp presentation timestamp of the frame
136      */
makeIvfFrameHeader(int size, long timestamp)137     private static byte[] makeIvfFrameHeader(int size, long timestamp){
138         byte[] frameHeader = new byte[12];
139         lay32Bits(frameHeader, 0, size);
140         lay64bits(frameHeader, 4, timestamp);
141         return frameHeader;
142     }
143 
144 
145     /**
146      * Lays least significant 16 bits of an int into 2 items of a byte array.
147      *
148      * Note that ordering is little-endian.
149      *
150      * @param array     the array to be modified
151      * @param index     index of the array to start laying down
152      * @param value     the integer to use least significant 16 bits
153      */
lay16Bits(byte[] array, int index, int value)154     private static void lay16Bits(byte[] array, int index, int value){
155         array[index] = (byte) (value);
156         array[index + 1] = (byte) (value >> 8);
157     }
158 
159     /**
160      * Lays an int into 4 items of a byte array.
161      *
162      * Note that ordering is little-endian.
163      *
164      * @param array     the array to be modified
165      * @param index     index of the array to start laying down
166      * @param value     the integer to use
167      */
lay32Bits(byte[] array, int index, int value)168     private static void lay32Bits(byte[] array, int index, int value){
169         for (int i = 0; i < 4; i++){
170             array[index + i] = (byte) (value >> (i * 8));
171         }
172     }
173 
174     /**
175      * Lays a long int into 8 items of a byte array.
176      *
177      * Note that ordering is little-endian.
178      *
179      * @param array     the array to be modified
180      * @param index     index of the array to start laying down
181      * @param value     the integer to use
182      */
lay64bits(byte[] array, int index, long value)183     private static void lay64bits(byte[] array, int index, long value){
184         for (int i = 0; i < 8; i++){
185             array[index + i] = (byte) (value >> (i * 8));
186         }
187     }
188 }
189