00001 #include <fcntl.h>
00002 #include <string.h>
00003 #include <errno.h>
00004
00005 #include "guicast.h"
00006 #include "pipe.h"
00007 #include "yuvstream.h"
00008 #include "interlacemodes.h"
00009
00010 YUVStream::YUVStream() {
00011 y4m_init_stream_info(&stream_info);
00012 y4m_init_frame_info(&frame_info);
00013 stream_fd = -1;
00014 stream_pipe= 0;
00015 frame_count = 0;
00016 frame_index = 0;
00017 }
00018
00019 YUVStream::~YUVStream() {
00020 y4m_fini_stream_info(&stream_info);
00021 y4m_fini_frame_info(&frame_info);
00022 if (frame_index) delete frame_index;
00023 close_fd();
00024 }
00025
00026
00027 int YUVStream::open_read(char *path) {
00028
00029 stream_fd = open(path, O_RDONLY);
00030
00031 if (stream_fd < 0) {
00032 printf("open(%s) failed: %s\n", path, strerror(errno));
00033 return 1;
00034 }
00035
00036 int result = read_header();
00037 if (result != Y4M_OK) {
00038 printf("bad YUV4MPEG2 header: %s\n", y4m_strerr(result));
00039 return 1;
00040 }
00041
00042
00043 if (frame_index == 0) {
00044 if (make_index() != 0) {
00045 return 1;
00046 }
00047 }
00048
00049 return 0;
00050 }
00051
00052
00053 int YUVStream::open_write(char *path, char *pipe) {
00054 if (pipe && *pipe) {
00055
00056 if (char *p = strchr(path, '|')) {
00057 pipe = p + 1;
00058 }
00059
00060 stream_pipe = new Pipe(pipe, path);
00061 if (stream_pipe->open_write() == 0) {
00062 stream_fd = stream_pipe->fd;
00063 return 0;
00064 }
00065 return 1;
00066 }
00067
00068 stream_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0666);
00069 if (stream_fd > 0) return 0;
00070
00071 printf("open(%s) failed: %s\n", path, strerror(errno));
00072 return 1;
00073 }
00074
00075
00076 void YUVStream::close_fd() {
00077 if (stream_pipe) {
00078 stream_pipe->close();
00079 stream_pipe = 0;
00080 stream_fd = -1;
00081 }
00082
00083 if (stream_fd >= 0) close(stream_fd);
00084 stream_fd = -1;
00085 }
00086
00087 int YUVStream::read_frame(uint8_t *yuv[3]) {
00088 int result = y4m_read_frame(stream_fd, &stream_info,
00089 &frame_info, yuv);
00090 if (result != Y4M_OK) {
00091 if (result != Y4M_ERR_EOF) {
00092 printf("read_frame() failed: %s\n",
00093 y4m_strerr(result));
00094 }
00095 return 1;
00096 }
00097
00098 return 0;
00099 }
00100
00101 int YUVStream::read_frame_raw(uint8_t *data, long frame_size) {
00102 #if (MJPEGTOOLS_Y4M_WRITE_FRAME_HEADER__3ARGS)
00103 int result = y4m_read_frame_header(stream_fd, &stream_info, &frame_info);
00104 #else
00105 int result = y4m_read_frame_header(stream_fd, &frame_info);
00106 #endif
00107 if (result != Y4M_OK) {
00108 printf("y4m_read_frame_header() failed: %s\n",
00109 y4m_strerr(result));
00110 return 1;
00111 }
00112 result = y4m_read(stream_fd, data, frame_size);
00113 if (result != Y4M_OK) {
00114 printf("y4m_read(%d) failed: %s\n",
00115 frame_size, y4m_strerr(result));
00116 return 1;
00117 }
00118 return 0;
00119 }
00120
00121 int YUVStream::write_frame(uint8_t *yuv[3]) {
00122 int result = y4m_write_frame(stream_fd, &stream_info,
00123 &frame_info, yuv);
00124 if (result != Y4M_OK) {
00125 printf("write_frame() failed: %s\n", y4m_strerr(result));
00126 return 1;
00127 }
00128 return 0;
00129 }
00130 int YUVStream::write_frame_raw(uint8_t *data, long frame_size) {
00131 #if (MJPEGTOOLS_Y4M_WRITE_FRAME_HEADER__3ARGS)
00132 int result = y4m_write_frame_header(stream_fd, &stream_info, &frame_info);
00133 #else
00134 int result = y4m_write_frame_header(stream_fd, &frame_info);
00135 #endif
00136 if (result != Y4M_OK) {
00137 printf("y4m_write_frame_header() failed: %s\n",
00138 y4m_strerr(result));
00139 return 1;
00140 }
00141 result = y4m_write(stream_fd, data, frame_size);
00142 if (result != Y4M_OK) {
00143 printf("y4m_write(%d) failed: %s\n",
00144 frame_size, y4m_strerr(result));
00145 return 1;
00146 }
00147 return 0;
00148 }
00149
00150 int YUVStream::make_index() {
00151 off_t position;
00152 uint8_t *yuv[3];
00153
00154
00155
00156
00157
00158
00159
00160 if (frame_index) delete frame_index;
00161 frame_index = new ArrayList<off_t>;
00162
00163 VFrame *frame = new VFrame(0, get_width(), get_height(), BC_YUV420P);
00164 yuv[0] = frame->get_y();
00165 yuv[1] = frame->get_u();
00166 yuv[2] = frame->get_v();
00167
00168
00169 position = lseek(stream_fd, 0, SEEK_CUR);
00170
00171
00172 frame_count = 0;
00173
00174 while (read_frame(yuv) == 0) {
00175
00176 frame_index->append(position);
00177 position = lseek(stream_fd, 0, SEEK_CUR);
00178 frame_count++;
00179 }
00180
00181
00182 lseek(stream_fd, frame_index->values[0], SEEK_SET);
00183
00184 delete frame;
00185
00186 return 0;
00187 }
00188
00189 int YUVStream::seek_frame(int64_t frame_number) {
00190 if (frame_number > frame_count ||
00191 frame_number < 0 ||
00192 frame_index == 0) {
00193 printf("seek_frame(%d) failed (frame_count=%d)\n",
00194 frame_number, frame_count);
00195 return 1;
00196 }
00197
00198 off_t position = frame_index->values[frame_number];
00199 if (position == 0) {
00200
00201 printf("seek_frame(%d): position was zero\n", frame_number);
00202 }
00203
00204 if (lseek(stream_fd, position, SEEK_SET) < 0) {
00205 printf("lseek(%d) failed: %s\n", position, strerror(errno));
00206 return 1;
00207 }
00208
00209 return 0;
00210 }
00211
00212 int YUVStream::read_header() {
00213 int result = y4m_read_stream_header(stream_fd, &stream_info);
00214 if (result != Y4M_OK) {
00215 printf("y4m_read_stream_header() failed: %s\n",
00216 y4m_strerr(result));
00217 return 1;
00218 }
00219 return 0;
00220 }
00221 int YUVStream::write_header() {
00222 int result = y4m_write_stream_header(stream_fd, &stream_info);
00223 if (result != Y4M_OK) {
00224 printf("y4m_write_stream_header() failed: %s\n",
00225 y4m_strerr(result));
00226 return 1;
00227 }
00228 return 0;
00229 }
00230
00231 int YUVStream::get_interlace() {
00232 return ilace_yuv4mpeg_to_bc(y4m_si_get_interlace(&stream_info));
00233 }
00234
00235 void YUVStream::set_interlace(int imode) {
00236 y4m_si_set_interlace(&stream_info, ilace_bc_to_yuv4mpeg(imode));
00237 }
00238
00239 int YUVStream::get_width() {
00240 return y4m_si_get_width(&stream_info);
00241 }
00242 void YUVStream::set_width(int width) {
00243 y4m_si_set_width(&stream_info, width);
00244 }
00245
00246 int YUVStream::get_height() {
00247 return y4m_si_get_height(&stream_info);
00248 }
00249 void YUVStream::set_height(int height) {
00250 y4m_si_set_height(&stream_info, height);
00251 }
00252
00253 double YUVStream::get_frame_rate() {
00254 y4m_ratio_t ratio = y4m_si_get_framerate(&stream_info);
00255 double frame_rate = (double) ratio.n / (double) ratio.d;
00256 return frame_rate;
00257 }
00258 void YUVStream::set_frame_rate(double frame_rate) {
00259 y4m_ratio_t ratio = mpeg_conform_framerate(frame_rate);
00260 y4m_si_set_framerate(&stream_info, ratio);
00261 }
00262
00263
00264
00265 double YUVStream::get_aspect_ratio() {
00266 y4m_ratio_t sar = y4m_si_get_sampleaspect(&stream_info);
00267 mpeg_aspect_code_t code =
00268 mpeg_guess_mpeg_aspect_code(2, sar,
00269 get_width(),
00270 get_height());
00271 y4m_ratio_t aspect_ratio = mpeg_framerate(code);
00272 if (aspect_ratio.d == 0) return 0;
00273 return (double) aspect_ratio.n / (double) aspect_ratio.n;
00274 }
00275 void YUVStream::set_aspect_ratio(double aspect_ratio) {
00276 y4m_ratio_t ratio;
00277 ratio.n = (int)(aspect_ratio * 10000);
00278 ratio.d = 10000;
00279 y4m_ratio_t sar = y4m_guess_sar(get_width(), get_height(),
00280 ratio);
00281 y4m_si_set_sampleaspect(&stream_info, sar);
00282 }