Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

yuvstream.C

Go to the documentation of this file.
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         // NOTE: reading from pipes would be very difficult without temp files
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         // generate index to frame position if not done yet
00043         if (frame_index == 0) {
00044                 if (make_index() != 0) {
00045                         return 1;
00046                 }
00047         }
00048 
00049         return 0;
00050 }
00051 
00052 // NOTE: path is opened as a pipe if contains '|'
00053 int YUVStream::open_write(char *path, char *pipe) {
00054         if (pipe && *pipe) {
00055                 // skip over the '|' if present
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         // NOTE: make_index() must be called after read_header().
00155 
00156         // NOTE: storing frame_index locally means it is destroyed too often.
00157         //       make_index() will be called 3 times per file.  If this
00158         //       becomes a performance problem, the index should be cached.
00159         //       Storing in 'asset' helps some, but still is done twice.
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         // note the start of the first frame
00169         position = lseek(stream_fd, 0, SEEK_CUR);
00170 
00171         // reset the frame count
00172         frame_count = 0;
00173 
00174         while (read_frame(yuv) == 0) {
00175                 // index is start position of each frame
00176                 frame_index->append(position);
00177                 position = lseek(stream_fd, 0, SEEK_CUR);
00178                 frame_count++;
00179         } 
00180 
00181         // rewind to the start of the first frame
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                 // because of header, position should never be zero
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 // FUTURE: these seem like a mess, possibly because I don't 
00264 //         properly understand "display aspect" vs "pixel aspect"
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 }

Generated on Sun Jan 8 13:39:02 2006 for Cinelerra-svn by  doxygen 1.4.4