r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / yuvstream.C
blobdf10d5eea15b6241075b98438684b6db67ccbc65
1 #include <fcntl.h>
2 #include <string.h>
3 #include <errno.h>
5 #include "guicast.h"
6 #include "pipe.h"
7 #include "yuvstream.h"
8 #include "interlacemodes.h"
10 YUVStream::YUVStream() { 
11         y4m_init_stream_info(&stream_info);
12         y4m_init_frame_info(&frame_info);
13         stream_fd = -1;
14         stream_pipe= 0;
15         frame_count = 0;
16         frame_index = 0;
19 YUVStream::~YUVStream() {               
20         y4m_fini_stream_info(&stream_info);
21         y4m_fini_frame_info(&frame_info);
22         if (frame_index) delete frame_index;
23         close_fd();
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);
31         if (stream_fd < 0) {
32                 printf("open(%s) failed: %s\n", path, strerror(errno));
33                 return 1;
34         }
36         int result = read_header();
37         if (result != Y4M_OK) {
38                 printf("bad YUV4MPEG2 header: %s\n", y4m_strerr(result));
39                 return 1;
40         }
42         // generate index to frame position if not done yet
43         if (frame_index == 0) {
44                 if (make_index() != 0) {
45                         return 1;
46                 }
47         }
49         return 0;
52 // NOTE: path is opened as a pipe if contains '|'
53 int YUVStream::open_write(char *path, char *pipe) {
54         if (pipe && *pipe) {
55                 // skip over the '|' if present
56                 if (char *p = strchr(path, '|')) {
57                         pipe = p + 1;
58                 }
60                 stream_pipe = new Pipe(pipe, path);
61                 if (stream_pipe->open_write() == 0) {
62                         stream_fd = stream_pipe->fd;
63                         return 0;
64                 }
65                 return 1;
66         }
68         stream_fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0666);
69         if (stream_fd > 0) return 0;
70         
71         printf("open(%s) failed: %s\n", path, strerror(errno));
72         return 1;
76 void YUVStream::close_fd() {
77         if (stream_pipe) {
78                 stream_pipe->close();
79                 stream_pipe = 0;
80                 stream_fd = -1;
81         }
82                 
83         if (stream_fd >= 0) close(stream_fd);
84         stream_fd = -1;
87 int YUVStream::read_frame(uint8_t *yuv[3]) {
88         int result =  y4m_read_frame(stream_fd, &stream_info, 
89                                   &frame_info, yuv);
90         if (result != Y4M_OK) {
91                 if (result != Y4M_ERR_EOF) {
92                         printf("read_frame() failed: %s\n", 
93                                y4m_strerr(result));
94                 }
95                 return 1;
96         }
98         return 0;
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", 
105                        y4m_strerr(result));
106                 return 1;
107         }
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));
112                 return 1;
113         }
114         return 0;
116                 
117 int YUVStream::write_frame(uint8_t *yuv[3]) {
118         int result = y4m_write_frame(stream_fd, &stream_info, 
119                                      &frame_info, yuv);
120         if (result != Y4M_OK) {
121                 printf("write_frame() failed: %s\n", y4m_strerr(result));
122                 return 1;
123         }
124         return 0;
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", 
130                        y4m_strerr(result));
131                 return 1;
132         }
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));
137                 return 1;
138         }
139         return 0;
140 }               
142 int YUVStream::make_index() {
143         off_t position;
144         uint8_t *yuv[3];
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
164         frame_count = 0;
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);
170                 frame_count++;
171         } 
173         // rewind to the start of the first frame
174         lseek(stream_fd, frame_index->values[0], SEEK_SET);
176         delete frame;
178         return 0;
181 int YUVStream::seek_frame(int64_t frame_number) {
182         if (frame_number > frame_count ||
183             frame_number < 0 ||
184             frame_index == 0) {
185                 printf("seek_frame(%d) failed (frame_count=%d)\n", 
186                        frame_number, frame_count);
187                 return 1;
188         }
190         off_t position = frame_index->values[frame_number];
191         if (position == 0) {
192                 // because of header, position should never be zero
193                 printf("seek_frame(%d): position was zero\n", frame_number);
194         }
196         if (lseek(stream_fd, position, SEEK_SET) < 0) {
197                 printf("lseek(%d) failed: %s\n", position, strerror(errno));
198                 return 1;
199         }
201         return 0;
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", 
208                        y4m_strerr(result));
209                 return 1;
210         }
211         return 0;
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", 
217                        y4m_strerr(result));
218                 return 1;
219         }
220         return 0;
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;
248         return frame_rate;
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, 
261                                             get_width(),
262                                             get_height());
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;
266 }               
267 void YUVStream::set_aspect_ratio(double aspect_ratio) {
268         y4m_ratio_t ratio;
269         ratio.n = (int)(aspect_ratio * 10000);
270         ratio.d = 10000;
271         y4m_ratio_t sar = y4m_guess_sar(get_width(), get_height(),
272                                         ratio);
273         y4m_si_set_sampleaspect(&stream_info, sar);