00001
00002 #include "vidl_vil1_mpegcodec_helper.h"
00003 #include <vidl_vil1/vidl_vil1_file_sequence.h>
00004 #include <vcl_iostream.h>
00005 #include <vcl_cstring.h>
00006 #include <vcl_cstdlib.h>
00007
00008 #ifdef HAVE_IO_H
00009 #include <fcntl.h>
00010 #include <io.h>
00011 #endif
00012
00013 vidl_vil1_mpegcodec_helper::vidl_vil1_mpegcodec_helper(vo_open_t * vopen,
00014 vcl_string filename,
00015 frame_buffer * buffers) :
00016 filename_(filename),output_open_(vopen)
00017 {
00018 demux_track_ = 0;
00019 demux_pid_ = 0;
00020 disable_accel_ = 0;
00021
00022
00023
00024 output_ = (vidl_vil1_mpegcodec_data*) vo_open (output_open_);
00025 output_->buffers = buffers;
00026 output_->output_format = vidl_vil1_mpegcodec_data::GREY;
00027 output_->last_frame_decoded = -2;
00028
00029 in_file_ = 0;
00030 init_ = false;
00031 mpeg2dec_ = new mpeg2dec_t;
00032 decoder_routine = 0;
00033 }
00034
00035 vidl_vil1_mpegcodec_helper::~vidl_vil1_mpegcodec_helper()
00036 {
00037 vcl_cout << "vidl_vil1_mpegcodec_helper::~vidl_vil1_mpegcodec_helper. entering.\n";
00038 vo_close (output_);
00039 if (in_file_)
00040 {
00041 in_file_->close();
00042 delete in_file_;
00043 }
00044
00045 delete mpeg2dec_;
00046
00047 vcl_cout << "vidl_vil1_mpegcodec_helper::~vidl_vil1_mpegcodec_helper. exiting.\n";
00048 }
00049
00050 bool
00051 vidl_vil1_mpegcodec_helper::init()
00052 {
00053 if (init_) return true;
00054
00055
00056 in_file_ = new vidl_vil1_file_sequence();
00057 in_file_->open(filename_.c_str());
00058
00059
00060
00061 uint32_t accel;
00062
00063
00064
00065
00066 accel = disable_accel_ ? 0 : MM_ACCEL_MLIB;
00067
00068 vo_accel (accel);
00069
00070 mpeg2_init (mpeg2dec_, accel,output_);
00071
00072 if (demux_pid_)
00073 {
00074
00075 chunk_size_ = 188;
00076 chunk_number_ = PACKETS;
00077 decoder_routine = &vidl_vil1_mpegcodec_helper::decode_ts;
00078 }
00079 else if (demux_track_)
00080 {
00081
00082 chunk_size_ = 1;
00083 chunk_number_ = BUFFER_SIZE;
00084 decoder_routine = &vidl_vil1_mpegcodec_helper::decode_ps;
00085 }
00086 else
00087 {
00088
00089 chunk_size_ = 1;
00090 chunk_number_ = BUFFER_SIZE;
00091 decoder_routine = &vidl_vil1_mpegcodec_helper::decode_es;
00092 }
00093
00094 init_ = true;
00095
00096 return true;
00097 }
00098
00099
00100
00101 int
00102 vidl_vil1_mpegcodec_helper::execute(decode_request * p)
00103 {
00104 if (!init_) init();
00105
00106 if (p->rt == decode_request::REWIND)
00107 {
00108 in_file_->seek(0);
00109 output_->framenum = -2;
00110 output_->last_frame_decoded = -2;
00111 return 0;
00112 }
00113
00114 output_->pending_decode = p;
00115
00116 do
00117 {
00118 int reads = in_file_->read(buffer_, (chunk_size_*chunk_number_));
00119 if (reads != (chunk_number_*chunk_size_)) return -1;
00120 (this->*decoder_routine)(reads);
00121 } while ((!p->done) &&
00122 (p->rt != decode_request::FILE_GRAB) &&
00123 (p->rt != decode_request::SKIP));
00124
00125 return 0;
00126 }
00127
00128 void
00129 vidl_vil1_mpegcodec_helper::decode_mpeg2 (uint8_t * buf, uint8_t * endb)
00130 {
00131 int num_frames;
00132
00133 num_frames = mpeg2_decode_data (mpeg2dec_, buf, endb);
00134
00135 output_->last_frame_decoded += num_frames;
00136 }
00137
00138 #define DEMUX_PAYLOAD_START 1
00139 int
00140 vidl_vil1_mpegcodec_helper::demux (uint8_t * buf, uint8_t * endb, int flags)
00141 {
00142 static int mpeg1_skip_table[16] = {
00143 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00144 };
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 #define DEMUX_HEADER 0
00161 #define DEMUX_DATA 1
00162 #define DEMUX_SKIP 2
00163 static int state = DEMUX_SKIP;
00164 static long int state_bytes = 0;
00165 static uint8_t head_buf[264];
00166
00167 uint8_t * header;
00168 long int bytes;
00169 int len;
00170
00171 #define NEEDBYTES(x) \
00172 do { \
00173 long int missing = (x) - bytes; \
00174 if (missing > 0) { \
00175 if (header == head_buf) { \
00176 if (missing <= endb - buf) { \
00177 vcl_memcpy(header + bytes, buf, missing); \
00178 buf += missing; \
00179 bytes = (x); \
00180 } else { \
00181 vcl_memcpy(header + bytes, buf, endb-buf); \
00182 state_bytes = bytes + (endb - buf); \
00183 return 0; \
00184 } \
00185 } else { \
00186 vcl_memcpy(head_buf, header, bytes); \
00187 state = DEMUX_HEADER; \
00188 state_bytes = bytes; \
00189 return 0; \
00190 } \
00191 } \
00192 } while (false)
00193
00194 #define DONEBYTES(x) \
00195 do { \
00196 if (header != head_buf) \
00197 buf = header + (x); \
00198 } while (false)
00199
00200 if (flags & DEMUX_PAYLOAD_START)
00201 goto payload_start;
00202 switch (state)
00203 {
00204 case DEMUX_HEADER:
00205 if (state_bytes > 0) {
00206 header = head_buf;
00207 bytes = state_bytes;
00208 goto continue_header;
00209 }
00210 break;
00211 case DEMUX_DATA:
00212 if (demux_pid_ || (state_bytes > endb - buf)) {
00213 decode_mpeg2 (buf, endb);
00214 state_bytes -= endb - buf;
00215 return 0;
00216 }
00217 decode_mpeg2 (buf, buf + state_bytes);
00218 buf += state_bytes;
00219 break;
00220 case DEMUX_SKIP:
00221 if (demux_pid_ || (state_bytes > endb - buf)) {
00222 state_bytes -= endb - buf;
00223 return 0;
00224 }
00225 buf += state_bytes;
00226 break;
00227 }
00228
00229 while (1)
00230 {
00231 if (demux_pid_) {
00232 state = DEMUX_SKIP;
00233 return 0;
00234 }
00235 payload_start:
00236 header = buf;
00237 bytes = endb - buf;
00238 continue_header:
00239 NEEDBYTES(4);
00240 if (header[0] || header[1] || (header[2] != 1))
00241 {
00242 if (demux_pid_) {
00243 state = DEMUX_SKIP;
00244 return 0;
00245 } else if (header != head_buf) {
00246 buf++;
00247 goto payload_start;
00248 } else {
00249 header[0] = header[1];
00250 header[1] = header[2];
00251 header[2] = header[3];
00252 bytes = 3;
00253 goto continue_header;
00254 }
00255 }
00256 if (demux_pid_) {
00257 if ((header[3] >= 0xe0) && (header[3] <= 0xef))
00258 goto pes;
00259 vcl_cerr << "bad stream id : " << header[3] << '\n';
00260 vcl_exit(1);
00261 }
00262 switch (header[3])
00263 {
00264 case 0xb9:
00265 return 1;
00266 case 0xba:
00267 NEEDBYTES(12);
00268 if ((header[4] & 0xc0) == 0x40) {
00269 NEEDBYTES(14);
00270 len = 14 + (header[13] & 7);
00271 NEEDBYTES(len);
00272 DONEBYTES(len);
00273
00274 } else if ((header[4] & 0xf0) == 0x20) {
00275 DONEBYTES(12);
00276
00277 } else {
00278 vcl_cerr << "weird pack header\n";
00279 vcl_exit(1);
00280 }
00281 break;
00282 default:
00283 if (header[3] == demux_track_)
00284 {
00285 pes:
00286 NEEDBYTES(7);
00287 if ((header[6] & 0xc0) == 0x80)
00288 {
00289 NEEDBYTES(9);
00290 len = 9 + header[8];
00291 NEEDBYTES(len);
00292
00293 if (header[7] & 0x80) {
00294 uint32_t pts;
00295
00296 pts = (((buf[9] >> 1) << 30) |
00297 (buf[10] << 22) | ((buf[11] >> 1) << 15) |
00298 (buf[12] << 7) | (buf[13] >> 1));
00299 mpeg2_pts (mpeg2dec_, pts);
00300 }
00301 }
00302 else
00303 {
00304 int len_skip;
00305 uint8_t * ptsbuf;
00306
00307 len = 7;
00308 while (header[len - 1] == 0xff) {
00309 len++;
00310 NEEDBYTES(len);
00311 if (len == 23) {
00312 vcl_cerr << "too much stuffing.\n";
00313 break;
00314 }
00315 }
00316 if ((header[len - 1] & 0xc0) == 0x40) {
00317 len += 2;
00318 NEEDBYTES(len);
00319 }
00320 len_skip = len;
00321 len += mpeg1_skip_table[header[len - 1] >> 4];
00322 NEEDBYTES(len);
00323
00324 ptsbuf = header + len_skip;
00325 if (ptsbuf[-1] & 0x20) {
00326 uint32_t pts;
00327
00328 pts = (((ptsbuf[-1] >> 1) << 30) |
00329 (ptsbuf[0] << 22) | ((ptsbuf[1] >> 1) << 15) |
00330 (ptsbuf[2] << 7) | (ptsbuf[3] >> 1));
00331 mpeg2_pts (mpeg2dec_, pts);
00332 }
00333 }
00334 DONEBYTES(len);
00335 bytes = 6 + (header[4] << 8) + header[5] - len;
00336 if (demux_pid_ || (bytes > endb - buf)) {
00337 decode_mpeg2 (buf, endb);
00338 state = DEMUX_DATA;
00339 state_bytes = bytes - (endb - buf);
00340 return 0;
00341 } else if (bytes > 0) {
00342 decode_mpeg2 (buf, buf + bytes);
00343 buf += bytes;
00344 }
00345 } else if (header[3] < 0xb9) {
00346 vcl_cerr << "looks like a video stream, not system stream\n";
00347 vcl_exit(1);
00348 } else {
00349 NEEDBYTES(6);
00350 DONEBYTES(6);
00351 bytes = (header[4] << 8) + header[5];
00352 if (bytes > endb - buf) {
00353 state = DEMUX_SKIP;
00354 state_bytes = bytes - (endb - buf);
00355 return 0;
00356 }
00357 buf += bytes;
00358 }
00359 }
00360 }
00361 }
00362
00363 bool
00364 vidl_vil1_mpegcodec_helper::decode_ps(int reads)
00365 {
00366 return 0 != demux (buffer_, buffer_+reads, 0);
00367 }
00368
00369 bool
00370 vidl_vil1_mpegcodec_helper::decode_ts(int packets)
00371 {
00372 uint8_t * buf;
00373 uint8_t * data;
00374 uint8_t * endb;
00375 int pid;
00376
00377 for (int i = 0; i < packets; i++)
00378 {
00379 buf = buffer_ + i * 188;
00380 endb = buf + 188;
00381 if (buf[0] != 0x47)
00382 {
00383 vcl_cerr << "bad sync byte\n";
00384 return false;
00385 }
00386 pid = ((buf[1] << 8) + buf[2]) & 0x1fff;
00387 if (pid != demux_pid_)
00388 continue;
00389 data = buf + 4;
00390 if (buf[3] & 0x20)
00391 {
00392 data = buf + 5 + buf[4];
00393 if (data > endb)
00394 continue;
00395 }
00396 if (buf[3] & 0x10)
00397 demux (data, endb, (buf[1] & 0x40) ? DEMUX_PAYLOAD_START : 0);
00398 }
00399 return true;
00400 }
00401
00402 bool
00403 vidl_vil1_mpegcodec_helper::decode_es(int reads)
00404 {
00405 decode_mpeg2 (buffer_, buffer_+reads);
00406 return true;
00407 }
00408
00409 void
00410 vidl_vil1_mpegcodec_helper::print()
00411 {
00412 vcl_cout << "about to print out decoder members.\n"
00413 << "frmt is: " << int(this->get_format()) << '\n'
00414 << "the last frame decoded is: " << output_->last_frame_decoded
00415 << "\nvidl_vil1_mpegcodec_helper::print. end.\n";
00416 }