8 #include "interlacemodes.h"
10 YUVStream::YUVStream() {
11 y4m_init_stream_info(&stream_info);
12 y4m_init_frame_info(&frame_info);
19 YUVStream::~YUVStream() {
20 y4m_fini_stream_info(&stream_info);
21 y4m_fini_frame_info(&frame_info);
22 if (frame_index) delete frame_index;
27 int YUVStream::open_read(char *path) {
28 // NOTE: reading from pipes would be very difficult without temp files
29 stream_fd = open(path, O_RDONLY);
32 printf("open(%s) failed: %s\n", path, strerror(errno));
36 int result = read_header();
37 if (result != Y4M_OK) {
38 printf("bad YUV4MPEG2 header: %s\n", y4m_strerr(result));
42 // generate index to frame position if not done yet
43 if (frame_index == 0) {
44 if (make_index() != 0) {
52 // NOTE: path is opened as a pipe if contains '|'
53 int YUVStream::open_write(char *path, char *pipe) {
55 // skip over the '|' if present
56 if (char *p = strchr(path, '|')) {
60 stream_pipe = new Pipe(pipe, path);
61 if (stream_pipe->open_write() == 0) {
62 stream_fd = stream_pipe->fd;
68 stream_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0666);
69 if (stream_fd > 0) return 0;
71 printf("open(%s) failed: %s\n", path, strerror(errno));
76 void YUVStream::close_fd() {
83 if (stream_fd >= 0) close(stream_fd);
87 int YUVStream::read_frame(uint8_t *yuv[3]) {
88 int result = y4m_read_frame(stream_fd, &stream_info,
90 if (result != Y4M_OK) {
91 if (result != Y4M_ERR_EOF) {
92 printf("read_frame() failed: %s\n",
101 int YUVStream::read_frame_raw(uint8_t *data, long frame_size) {
102 int result = y4m_read_frame_header(stream_fd, &frame_info);
103 if (result != Y4M_OK) {
104 printf("y4m_read_frame_header() failed: %s\n",
108 result = y4m_read(stream_fd, data, frame_size);
109 if (result != Y4M_OK) {
110 printf("y4m_read(%d) failed: %s\n",
111 frame_size, y4m_strerr(result));
117 int YUVStream::write_frame(uint8_t *yuv[3]) {
118 int result = y4m_write_frame(stream_fd, &stream_info,
120 if (result != Y4M_OK) {
121 printf("write_frame() failed: %s\n", y4m_strerr(result));
126 int YUVStream::write_frame_raw(uint8_t *data, long frame_size) {
127 int result = y4m_write_frame_header(stream_fd, &frame_info);
128 if (result != Y4M_OK) {
129 printf("y4m_write_frame_header() failed: %s\n",
133 result = y4m_write(stream_fd, data, frame_size);
134 if (result != Y4M_OK) {
135 printf("y4m_write(%d) failed: %s\n",
136 frame_size, y4m_strerr(result));
142 int YUVStream::make_index() {
146 // NOTE: make_index() must be called after read_header().
148 // NOTE: storing frame_index locally means it is destroyed too often.
149 // make_index() will be called 3 times per file. If this
150 // becomes a performance problem, the index should be cached.
151 // Storing in 'asset' helps some, but still is done twice.
152 if (frame_index) delete frame_index;
153 frame_index = new ArrayList<off_t>;
155 VFrame *frame = new VFrame(0, get_width(), get_height(), BC_YUV420P);
156 yuv[0] = frame->get_y();
157 yuv[1] = frame->get_u();
158 yuv[2] = frame->get_v();
160 // note the start of the first frame
161 position = lseek(stream_fd, 0, SEEK_CUR);
163 // reset the frame count
166 while (read_frame(yuv) == 0) {
167 // index is start position of each frame
168 frame_index->append(position);
169 position = lseek(stream_fd, 0, SEEK_CUR);
173 // rewind to the start of the first frame
174 lseek(stream_fd, frame_index->values[0], SEEK_SET);
181 int YUVStream::seek_frame(int64_t frame_number) {
182 if (frame_number > frame_count ||
185 printf("seek_frame(%d) failed (frame_count=%d)\n",
186 frame_number, frame_count);
190 off_t position = frame_index->values[frame_number];
192 // because of header, position should never be zero
193 printf("seek_frame(%d): position was zero\n", frame_number);
196 if (lseek(stream_fd, position, SEEK_SET) < 0) {
197 printf("lseek(%d) failed: %s\n", position, strerror(errno));
204 int YUVStream::read_header() {
205 int result = y4m_read_stream_header(stream_fd, &stream_info);
206 if (result != Y4M_OK) {
207 printf("y4m_read_stream_header() failed: %s\n",
213 int YUVStream::write_header() {
214 int result = y4m_write_stream_header(stream_fd, &stream_info);
215 if (result != Y4M_OK) {
216 printf("y4m_write_stream_header() failed: %s\n",
223 int YUVStream::get_interlace() {
224 return ilace_yuv4mpeg_to_bc(y4m_si_get_interlace(&stream_info));
227 void YUVStream::set_interlace(int imode) {
228 y4m_si_set_interlace(&stream_info, ilace_bc_to_yuv4mpeg(imode));
231 int YUVStream::get_width() {
232 return y4m_si_get_width(&stream_info);
234 void YUVStream::set_width(int width) {
235 y4m_si_set_width(&stream_info, width);
238 int YUVStream::get_height() {
239 return y4m_si_get_height(&stream_info);
241 void YUVStream::set_height(int height) {
242 y4m_si_set_height(&stream_info, height);
245 double YUVStream::get_frame_rate() {
246 y4m_ratio_t ratio = y4m_si_get_framerate(&stream_info);
247 double frame_rate = (double) ratio.n / (double) ratio.d;
250 void YUVStream::set_frame_rate(double frame_rate) {
251 y4m_ratio_t ratio = mpeg_conform_framerate(frame_rate);
252 y4m_si_set_framerate(&stream_info, ratio);
255 // FUTURE: these seem like a mess, possibly because I don't
256 // properly understand "display aspect" vs "pixel aspect"
257 double YUVStream::get_aspect_ratio() {
258 y4m_ratio_t sar = y4m_si_get_sampleaspect(&stream_info);
259 mpeg_aspect_code_t code =
260 mpeg_guess_mpeg_aspect_code(2, sar,
263 y4m_ratio_t aspect_ratio = mpeg_framerate(code);
264 if (aspect_ratio.d == 0) return 0;
265 return (double) aspect_ratio.n / (double) aspect_ratio.n;
267 void YUVStream::set_aspect_ratio(double aspect_ratio) {
269 ratio.n = (int)(aspect_ratio * 10000);
271 y4m_ratio_t sar = y4m_guess_sar(get_width(), get_height(),
273 y4m_si_set_sampleaspect(&stream_info, sar);