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 #if (MJPEGTOOLS_Y4M_WRITE_FRAME_HEADER__3ARGS)
103 int result = y4m_read_frame_header(stream_fd, &stream_info, &frame_info);
105 int result = y4m_read_frame_header(stream_fd, &frame_info);
107 if (result != Y4M_OK) {
108 printf("y4m_read_frame_header() failed: %s\n",
112 result = y4m_read(stream_fd, data, frame_size);
113 if (result != Y4M_OK) {
114 printf("y4m_read(%d) failed: %s\n",
115 frame_size, y4m_strerr(result));
121 int YUVStream::write_frame(uint8_t *yuv[3]) {
122 int result = y4m_write_frame(stream_fd, &stream_info,
124 if (result != Y4M_OK) {
125 printf("write_frame() failed: %s\n", y4m_strerr(result));
130 int YUVStream::write_frame_raw(uint8_t *data, long frame_size) {
131 #if (MJPEGTOOLS_Y4M_WRITE_FRAME_HEADER__3ARGS)
132 int result = y4m_write_frame_header(stream_fd, &stream_info, &frame_info);
134 int result = y4m_write_frame_header(stream_fd, &frame_info);
136 if (result != Y4M_OK) {
137 printf("y4m_write_frame_header() failed: %s\n",
141 result = y4m_write(stream_fd, data, frame_size);
142 if (result != Y4M_OK) {
143 printf("y4m_write(%d) failed: %s\n",
144 frame_size, y4m_strerr(result));
150 int YUVStream::make_index() {
154 // NOTE: make_index() must be called after read_header().
156 // NOTE: storing frame_index locally means it is destroyed too often.
157 // make_index() will be called 3 times per file. If this
158 // becomes a performance problem, the index should be cached.
159 // Storing in 'asset' helps some, but still is done twice.
160 if (frame_index) delete frame_index;
161 frame_index = new ArrayList<off_t>;
163 VFrame *frame = new VFrame(0, get_width(), get_height(), BC_YUV420P);
164 yuv[0] = frame->get_y();
165 yuv[1] = frame->get_u();
166 yuv[2] = frame->get_v();
168 // note the start of the first frame
169 position = lseek(stream_fd, 0, SEEK_CUR);
171 // reset the frame count
174 while (read_frame(yuv) == 0) {
175 // index is start position of each frame
176 frame_index->append(position);
177 position = lseek(stream_fd, 0, SEEK_CUR);
181 // rewind to the start of the first frame
182 lseek(stream_fd, frame_index->values[0], SEEK_SET);
189 int YUVStream::seek_frame(int64_t frame_number) {
190 if (frame_number > frame_count ||
193 printf("seek_frame(%d) failed (frame_count=%d)\n",
194 frame_number, frame_count);
198 off_t position = frame_index->values[frame_number];
200 // because of header, position should never be zero
201 printf("seek_frame(%d): position was zero\n", frame_number);
204 if (lseek(stream_fd, position, SEEK_SET) < 0) {
205 printf("lseek(%d) failed: %s\n", position, strerror(errno));
212 int YUVStream::read_header() {
213 int result = y4m_read_stream_header(stream_fd, &stream_info);
214 if (result != Y4M_OK) {
215 printf("y4m_read_stream_header() failed: %s\n",
221 int YUVStream::write_header() {
222 int result = y4m_write_stream_header(stream_fd, &stream_info);
223 if (result != Y4M_OK) {
224 printf("y4m_write_stream_header() failed: %s\n",
231 int YUVStream::get_interlace() {
232 return ilace_yuv4mpeg_to_bc(y4m_si_get_interlace(&stream_info));
235 void YUVStream::set_interlace(int imode) {
236 y4m_si_set_interlace(&stream_info, ilace_bc_to_yuv4mpeg(imode));
239 int YUVStream::get_width() {
240 return y4m_si_get_width(&stream_info);
242 void YUVStream::set_width(int width) {
243 y4m_si_set_width(&stream_info, width);
246 int YUVStream::get_height() {
247 return y4m_si_get_height(&stream_info);
249 void YUVStream::set_height(int height) {
250 y4m_si_set_height(&stream_info, height);
253 double YUVStream::get_frame_rate() {
254 y4m_ratio_t ratio = y4m_si_get_framerate(&stream_info);
255 double frame_rate = (double) ratio.n / (double) ratio.d;
258 void YUVStream::set_frame_rate(double frame_rate) {
259 y4m_ratio_t ratio = mpeg_conform_framerate(frame_rate);
260 y4m_si_set_framerate(&stream_info, ratio);
263 // FUTURE: these seem like a mess, possibly because I don't
264 // properly understand "display aspect" vs "pixel aspect"
265 double YUVStream::get_aspect_ratio() {
266 y4m_ratio_t sar = y4m_si_get_sampleaspect(&stream_info);
267 mpeg_aspect_code_t code =
268 mpeg_guess_mpeg_aspect_code(2, sar,
271 y4m_ratio_t aspect_ratio = mpeg_framerate(code);
272 if (aspect_ratio.d == 0) return 0;
273 return (double) aspect_ratio.n / (double) aspect_ratio.n;
275 void YUVStream::set_aspect_ratio(double aspect_ratio) {
277 ratio.n = (int)(aspect_ratio * 10000);
279 y4m_ratio_t sar = y4m_guess_sar(get_width(), get_height(),
281 y4m_si_set_sampleaspect(&stream_info, sar);