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