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