1 /*
2 * extract_yuv.c
3 *
4 * Copyright (C) Thomas Oestreich - June 2001
5 * Copyright (C) Francesco Romani - March 2006
6 *
7 * This file is part of transcode, a video stream processing tool
8 *
9 * transcode is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * transcode is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with GNU Make; see the file COPYING. If not, write to
21 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25 #include "config.h"
26
27 #include "transcode.h"
28 #include "framebuffer.h"
29 #include "tcinfo.h"
30 #include "libtc/libtc.h"
31 #include "libtc/ratiocodes.h"
32 #include "libtc/tcframes.h"
33
34 #include "ioaux.h"
35 #include "avilib/avilib.h"
36 #include "tc.h"
37
38 #if defined HAVE_MJPEGTOOLS
39 /* assert using new code (FIXME?) */
40
41 #if defined(HAVE_MJPEGTOOLS_INC)
42 #include "yuv4mpeg.h"
43 #include "mpegconsts.h"
44 #else
45 #include "mjpegtools/yuv4mpeg.h"
46 #include "mjpegtools/mpegconsts.h"
47 #endif
48
49 /* ------------------------------------------------------------
50 *
51 * yuv extract thread
52 *
53 * magic: TC_MAGIC_YUV4MPEG
54 * TC_MAGIC_RAW <-- default
55 *
56 *
57 * ------------------------------------------------------------*/
58
59
extract_yuv_y4m(info_t * ipipe)60 static int extract_yuv_y4m(info_t *ipipe)
61 {
62 vframe_list_t *vptr = NULL;
63 uint8_t *planes[3];
64 int planesize[3];
65 int ch_mode, w, h, ret = 0, i = 0, errnum;
66
67 y4m_frame_info_t frameinfo;
68 y4m_stream_info_t streaminfo;
69
70 /* initialize stream-information */
71 y4m_accept_extensions(1);
72 y4m_init_stream_info(&streaminfo);
73 y4m_init_frame_info(&frameinfo);
74
75 errnum = y4m_read_stream_header(ipipe->fd_in, &streaminfo);
76 if (errnum != Y4M_OK) {
77 tc_log_error(__FILE__, "Couldn't read YUV4MPEG header: %s!",
78 y4m_strerr (errnum));
79 return 1;
80 }
81 if (y4m_si_get_plane_count(&streaminfo) != 3) {
82 tc_log_error(__FILE__, "Only 3-plane formats supported");
83 return 1;
84 }
85 ch_mode = y4m_si_get_chroma(&streaminfo);
86 if (ch_mode != Y4M_CHROMA_420JPEG && ch_mode != Y4M_CHROMA_420MPEG2
87 && ch_mode != Y4M_CHROMA_420PALDV) {
88 tc_log_error(__FILE__, "sorry, chroma mode `%s' (%i) not supported",
89 y4m_chroma_description(ch_mode), ch_mode);
90 return 1;
91 }
92
93 w = y4m_si_get_width(&streaminfo);
94 h = y4m_si_get_height(&streaminfo);
95 vptr = tc_new_video_frame(w, h, TC_CODEC_YUV420P, TC_TRUE);
96
97 if (!vptr) {
98 tc_log_error(__FILE__, "can't allocate buffer (%ix%i)", w, h);
99 return 1;
100 }
101 planes[0] = vptr->video_buf_Y[0];
102 planes[1] = vptr->video_buf_U[0];
103 planes[2] = vptr->video_buf_V[0];
104
105 planesize[0] = y4m_si_get_plane_length(&streaminfo, 0);
106 planesize[1] = y4m_si_get_plane_length(&streaminfo, 1);
107 planesize[2] = y4m_si_get_plane_length(&streaminfo, 2);
108
109 while (1) {
110 errnum = y4m_read_frame(ipipe->fd_in, &streaminfo, &frameinfo, planes);
111 if (errnum != Y4M_OK) {
112 break;
113 }
114 for (i = 0; i < 3; i++) {
115 ret = tc_pwrite(ipipe->fd_out, planes[i], planesize[i]);
116 if (ret != planesize[i]) {
117 tc_log_perror(__FILE__, "error while writing output data");
118 break;
119 }
120 }
121 }
122
123 tc_del_video_frame(vptr);
124 y4m_fini_frame_info(&frameinfo);
125 y4m_fini_stream_info(&streaminfo);
126
127 return 0;
128 }
129
extract_yuv_avi(info_t * ipipe)130 static int extract_yuv_avi(info_t *ipipe)
131 {
132 avi_t *avifile=NULL;
133 char *video;
134
135 int key;
136 long frames, bytes, n;
137
138 if (ipipe->nav_seek_file) {
139 avifile = AVI_open_indexfd(ipipe->fd_in, 0, ipipe->nav_seek_file);
140 } else {
141 avifile = AVI_open_fd(ipipe->fd_in, 1);
142 }
143 if (NULL == avifile) {
144 AVI_print_error("AVI open");
145 return 1;
146 }
147
148 // read video info;
149 frames = AVI_video_frames(avifile);
150 if (ipipe->frame_limit[1] < frames) {
151 frames=ipipe->frame_limit[1];
152 }
153
154 if (ipipe->verbose & TC_STATS) {
155 tc_log_info(__FILE__, "%ld video frames", frames);
156 }
157 // allocate space, assume max buffer size
158 video = tc_bufalloc(SIZE_RGB_FRAME);
159 if (video == NULL) {
160 tc_log_error(__FILE__, "out of memory");
161 return 1;
162 }
163
164 AVI_set_video_position(avifile, ipipe->frame_limit[0]);
165 for (n = ipipe->frame_limit[0]; n <= frames; ++n) {
166 bytes = AVI_read_frame(avifile, video, &key);
167 if (bytes < 0) {
168 return 1;
169 }
170 if (tc_pwrite(ipipe->fd_out, video, bytes) != bytes) {
171 tc_log_perror(__FILE__, "error while writing output data");
172 return 1;
173 }
174 }
175 tc_buffree(video);
176
177 return 0;
178 }
179
extract_yuv_raw(info_t * ipipe)180 static int extract_yuv_raw(info_t *ipipe)
181 {
182 if (ipipe->magic == TC_MAGIC_UNKNOWN) {
183 tc_log_warn(__FILE__, "no file type specified, assuming (%s)",
184 filetype(TC_MAGIC_RAW));
185 }
186 return tc_preadwrite(ipipe->fd_in, ipipe->fd_out);
187 }
188
extract_yuv(info_t * ipipe)189 void extract_yuv(info_t *ipipe)
190 {
191 int error = 0;
192
193 switch(ipipe->magic) {
194 case TC_MAGIC_YUV4MPEG:
195 error = extract_yuv_y4m(ipipe);
196 break;
197 case TC_MAGIC_AVI:
198 error = extract_yuv_avi(ipipe);
199 break;
200 case TC_MAGIC_RAW:
201 default:
202 error = extract_yuv_raw(ipipe);
203 break;
204 }
205 if (error) {
206 tc_log_error(__FILE__, "write failed");
207 import_exit(error);
208 }
209 }
210
probe_yuv(info_t * ipipe)211 void probe_yuv(info_t *ipipe)
212 {
213 int errnum = Y4M_OK;
214 y4m_frame_info_t frameinfo;
215 y4m_stream_info_t streaminfo;
216 y4m_ratio_t r;
217
218 /* initialize stream-information */
219 y4m_accept_extensions(1);
220 y4m_init_stream_info(&streaminfo);
221 y4m_init_frame_info(&frameinfo);
222
223 errnum = y4m_read_stream_header(ipipe->fd_in, &streaminfo);
224 if (errnum != Y4M_OK) {
225 tc_log_error(__FILE__, "Couldn't read YUV4MPEG header: %s!",
226 y4m_strerr(errnum));
227 import_exit(1);
228 }
229
230 ipipe->probe_info->width = y4m_si_get_width(&streaminfo);
231 ipipe->probe_info->height = y4m_si_get_height(&streaminfo);
232
233 r = y4m_si_get_framerate(&streaminfo);
234 ipipe->probe_info->fps = (double)r.n / (double)r.d;
235 tc_frc_code_from_ratio(&(ipipe->probe_info->frc), r.n, r.d);
236
237 r = y4m_si_get_sampleaspect(&streaminfo);
238 tc_asr_code_from_ratio(&(ipipe->probe_info->asr), r.n, r.d);
239
240 ipipe->probe_info->codec=TC_CODEC_YUV420P;
241 ipipe->probe_info->magic=TC_MAGIC_YUV4MPEG;
242
243 y4m_fini_frame_info(&frameinfo);
244 y4m_fini_stream_info(&streaminfo);
245 }
246
247 #else /* HAVE_MJPEGTOOLS */
248
extract_yuv(info_t * ipipe)249 void extract_yuv(info_t *ipipe)
250 {
251 tc_log_error(__FILE__, "No support for YUV4MPEG compiled in.");
252 tc_log_error(__FILE__, "Recompile with mjpegtools support enabled.");
253 import_exit(1);
254 }
255
probe_yuv(info_t * ipipe)256 void probe_yuv(info_t * ipipe)
257 {
258 tc_log_error(__FILE__, "No support for YUV4MPEG compiled in.");
259 tc_log_error(__FILE__, "Recompile with mjpegtools support enabled.");
260 ipipe->probe_info->codec = TC_CODEC_UNKNOWN;
261 ipipe->probe_info->magic = TC_MAGIC_UNKNOWN;
262 }
263
264 #endif /* HAVE_MJPEGTOOLS */
265
266 /*************************************************************************/
267
268 /*
269 * Local variables:
270 * c-file-style: "stroustrup"
271 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
272 * indent-tabs-mode: nil
273 * End:
274 *
275 * vim: expandtab shiftwidth=4:
276 */
277