1 /*
2  *  decode_mpeg2.c
3  *
4  *  Copyright (C) Thomas Oestreich - June 2001
5  *  Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
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 "transcode.h"
26 #include "tcinfo.h"
27 
28 #include "ioaux.h"
29 #include "tc.h"
30 
31 #include "libtc/libtc.h"
32 
33 #if defined(HAVE_LIBMPEG2) && defined(HAVE_LIBMPEG2CONVERT)
34 
35 #include <mpeg2dec/mpeg2.h>
36 #include <mpeg2dec/mpeg2convert.h>
37 
38 #define BUFFER_SIZE 262144
39 static uint8_t buffer[BUFFER_SIZE];
40 
41 /* ------------------------------------------------------------
42  * helper functions
43  * ------------------------------------------------------------*/
44 
45 typedef void (*WriteDataFn)(decode_t *decode, const mpeg2_info_t *info,
46                             const mpeg2_sequence_t *sequence);
47 
show_accel(uint32_t mp_ac)48 static void show_accel(uint32_t mp_ac)
49 {
50     tc_log_info(__FILE__, "libmpeg2 acceleration: %s",
51                 (mp_ac & MPEG2_ACCEL_X86_3DNOW)  ? "3dnow" :
52                 (mp_ac & MPEG2_ACCEL_X86_MMXEXT) ? "mmxext" :
53                 (mp_ac & MPEG2_ACCEL_X86_MMX)    ? "mmx" :
54                                                    "none (plain C)");
55 }
56 
57 #define WRITE_DATA(PBUF, LEN, TAG) do { \
58     int ret = tc_pwrite(decode->fd_out, PBUF, LEN); \
59     if(LEN != ret) { \
60         tc_log_error(__FILE__, "failed to write %s data" \
61                                " of frame (len=%i)", \
62                                TAG, ret); \
63         import_exit(1); \
64     } \
65 } while (0)
66 
67 
write_rgb24(decode_t * decode,const mpeg2_info_t * info,const mpeg2_sequence_t * sequence)68 static void write_rgb24(decode_t *decode, const mpeg2_info_t *info,
69                         const mpeg2_sequence_t *sequence)
70 {
71     int len = 0;
72     /* FIXME: move to libtc/tcframes routines? */
73 
74     len = 3 * info->sequence->width * info->sequence->height;
75     WRITE_DATA(info->display_fbuf->buf[0], len, "RGB");
76 }
77 
write_yuv420p(decode_t * decode,const mpeg2_info_t * info,const mpeg2_sequence_t * sequence)78 static void write_yuv420p(decode_t *decode, const mpeg2_info_t *info,
79                           const mpeg2_sequence_t *sequence)
80 {
81     static const char *plane_id[] = { "Y", "U", "V" };
82     int len = 0;
83     /* FIXME: move to libtc/tcframes routines? */
84 
85     len = sequence->width * sequence->height;
86     WRITE_DATA(info->display_fbuf->buf[0], len, plane_id[0]);
87 
88     len = sequence->chroma_width * sequence->chroma_height;
89     WRITE_DATA(info->display_fbuf->buf[1], len, plane_id[1]);
90     WRITE_DATA(info->display_fbuf->buf[2], len, plane_id[2]);
91 }
92 
93 
94 /* ------------------------------------------------------------
95  * decoder entry point
96  * ------------------------------------------------------------*/
97 
decode_mpeg2(decode_t * decode)98 void decode_mpeg2(decode_t *decode)
99 {
100     mpeg2dec_t *decoder = NULL;
101     const mpeg2_info_t *info = NULL;
102     const mpeg2_sequence_t *sequence = NULL;
103     mpeg2_state_t state;
104     size_t size;
105     uint32_t ac = 0;
106 
107     WriteDataFn writer = write_yuv420p;
108     if (decode->format == TC_CODEC_RGB) {
109         tc_log_info(__FILE__, "using libmpeg2convert"
110                               " RGB24 conversion");
111         writer = write_rgb24;
112     }
113 
114     ac = mpeg2_accel(MPEG2_ACCEL_DETECT);
115     show_accel(ac);
116 
117     decoder = mpeg2_init();
118     if (decoder == NULL) {
119         tc_log_error(__FILE__, "Could not allocate a decoder object.");
120         import_exit(1);
121     }
122     info = mpeg2_info(decoder);
123 
124     size = (size_t)-1;
125     do {
126         state = mpeg2_parse(decoder);
127         sequence = info->sequence;
128         switch (state) {
129           case STATE_BUFFER:
130             size = tc_pread(decode->fd_in, buffer, BUFFER_SIZE);
131             mpeg2_buffer(decoder, buffer, buffer + size);
132             break;
133           case STATE_SEQUENCE:
134             if (decode->format == TC_CODEC_RGB) {
135                 mpeg2_convert(decoder, mpeg2convert_rgb24, NULL);
136             }
137             break;
138           case STATE_SLICE:
139           case STATE_END:
140           case STATE_INVALID_END:
141             if (info->display_fbuf) {
142                 writer(decode, info, sequence);
143             }
144             break;
145           default:
146             /* can't happen */
147             break;
148         }
149     } while (size);
150 
151     mpeg2_close(decoder);
152     import_exit(0);
153 }
154 
155 #else /* defined(HAVE_LIBMPEG2) && defined(HAVE_LIBMPEG2CONVERT) */
156 
decode_mpeg2(decode_t * decode)157 void decode_mpeg2(decode_t *decode)
158 {
159     tc_log_error(__FILE__, "No support for MPEG2 configured -- exiting");
160     import_exit(1);
161 }
162 
163 
164 #endif /* defined(HAVE_LIBMPEG2) && defined(HAVE_LIBMPEG2CONVERT) */
165 
166 
167 /*************************************************************************/
168 
169 /*
170  * Local variables:
171  *   c-file-style: "stroustrup"
172  *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
173  *   indent-tabs-mode: nil
174  * End:
175  *
176  * vim: expandtab shiftwidth=4:
177  */
178