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