📄 fame_syntax_mpeg1.c
字号:
/* libfame - Fast Assembly MPEG Encoder Library Copyright (C) 2000-2001 Vivien Chappelier This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include "fame.h"#include "fame_malloc.h"#include "fame_syntax.h"#include "fame_bitbuffer.h"#include "fame_syntax_mpeg1.h"#include "table_zigzag_mpeg1.h"#include "table_rlehuff_mpeg1.h"#include "table_dc_mpeg1.h"#include "table_cbp_mpeg1.h"#include "table_quant_mpeg1.h"#include "table_clip_mpeg1.h"#include "table_mv.h"/* The header codes */#define SEQUENCE_START_CODE 0x1b3#define SEQUENCE_END_CODE 0x1b9#define GOP_START_CODE 0x1b8#define PICT_START_CODE 0x100#define SLICE_BASE_CODE 0x101/* The frame type values */#define I_FRAME 1#define P_FRAME 2#define B_FRAME 3static void mpeg1_init(fame_syntax_t *syntax, int mb_width, int mb_height, unsigned char **intra_default_matrix, unsigned char **inter_default_matrix, unsigned char *intra_dc_y_scale_table, unsigned char *intra_dc_c_scale_table, fame_mismatch_t *mismatch_type, unsigned int flags);static void mpeg1_close(fame_syntax_t *syntax);static void mpeg1_use(fame_syntax_t *syntax, unsigned char *buffer, int size);static int mpeg1_flush(fame_syntax_t *syntax);static void mpeg1_start_sequence(fame_syntax_t *syntax, int width, int height, int fps_num, int fps_den, int size, int bitrate);static void mpeg1_start_GOP(fame_syntax_t *syntax, int frame);static void mpeg1_start_picture(fame_syntax_t *syntax, char frame_type, int frame_number, fame_box_t *box, int rounding_control, int search_range);static void mpeg1_start_slice(fame_syntax_t *syntax, int vpos, int length, unsigned char qscale);static void mpeg1_end_slice(fame_syntax_t *syntax);static void mpeg1_end_sequence(fame_syntax_t *syntax);static void mpeg1_predict_vector(fame_syntax_t *syntax, int mb_x, int mb_y, int k, fame_motion_vector_t *mv);static void mpeg1_compute_chrominance_vectors(fame_syntax_t *syntax, fame_motion_vector_t *vectors, unsigned char pattern);static int mpeg1_write_intra_mb(fame_syntax_t *syntax, int mb_x, int mb_y, short *blocks[6], unsigned char *bab, unsigned char *bab_map, fame_bab_t bab_type, int dquant, unsigned char pattern);static int mpeg1_write_inter_mb(fame_syntax_t *syntax, int mb_x, int mb_y, short *blocks[6], unsigned char *bab, unsigned char *bab_map, fame_bab_t bab_type, int dquant, unsigned char pattern, fame_motion_vector_t *forward, fame_motion_vector_t *backward, fame_motion_coding_t motion_coding);FAME_CONSTRUCTOR(fame_syntax_mpeg1_t){ FAME_OBJECT(this)->name = "MPEG-1 bitstream syntax"; FAME_SYNTAX(this)->init = mpeg1_init; FAME_SYNTAX(this)->use = mpeg1_use; FAME_SYNTAX(this)->flush = mpeg1_flush; FAME_SYNTAX(this)->start_sequence = mpeg1_start_sequence; FAME_SYNTAX(this)->start_GOP = mpeg1_start_GOP; FAME_SYNTAX(this)->start_picture = mpeg1_start_picture; FAME_SYNTAX(this)->start_slice = mpeg1_start_slice; FAME_SYNTAX(this)->end_slice = mpeg1_end_slice; FAME_SYNTAX(this)->end_sequence = mpeg1_end_sequence; FAME_SYNTAX(this)->predict_vector = mpeg1_predict_vector; FAME_SYNTAX(this)->compute_chrominance_vectors = mpeg1_compute_chrominance_vectors; FAME_SYNTAX(this)->write_intra_mb = mpeg1_write_intra_mb; FAME_SYNTAX(this)->write_inter_mb = mpeg1_write_inter_mb; FAME_SYNTAX(this)->close = mpeg1_close; return(this);}static void inline mpeg1_init_vlc_table(fame_vlc_t *vlc){ int z, l; for(l = -255; l < 256; l++) { for(z = 0; z < 64; z++) { if(z < HUFFMAXRUN && l < rlehuff_max_level[z] && l > -rlehuff_max_level[z]) { /* encode value and number of z */ vlc->code = huff_table[z][l+rlehuff_max_level[z]-1]; vlc->length =huff_bits[z][l+rlehuff_max_level[z]-1]; } else { /* escape code and encode number of z */ vlc->code = ((0x40+z) << rlehuff_table[l+255].length) | rlehuff_table[l+255].code; vlc->length = rlehuff_table[l+255].length+12; } vlc++; } }}static void inline mpeg1_next_start_code(fame_bitbuffer_t *buffer){ if(bitbuffer_padding(buffer) != 0) bitbuffer_write(buffer, 0x00, bitbuffer_padding(buffer));}static void mpeg1_init(fame_syntax_t *syntax, int mb_width, int mb_height, unsigned char **intra_matrix, unsigned char **inter_matrix, unsigned char *intra_dc_y_scale_table, unsigned char *intra_dc_c_scale_table, fame_mismatch_t *mismatch_type, unsigned int flags){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); int qscale; syntax_mpeg1->mb_width = mb_width; syntax_mpeg1->mb_height = mb_height; syntax_mpeg1->fps_num = 25; syntax_mpeg1->fps_den = 1; /* initialize vlc_table */ syntax_mpeg1->vlc_table = (fame_vlc_t *) fame_malloc(64*511*sizeof(fame_vlc_t)); mpeg1_init_vlc_table(syntax_mpeg1->vlc_table); /* center vlc_table */ syntax_mpeg1->vlc_table += 64*255; /* fill in quantization tables */ if(*intra_matrix) { /* TODO: flag to write matrix to bitstream */ /* TEMP: use default matrix instead */ FAME_WARNING("Custom quantisation matrix not supported, using default.\n"); *intra_matrix = mpeg1_intra_quantisation_table; } else { *intra_matrix = mpeg1_intra_quantisation_table; } if(*inter_matrix) { /* TODO: flag to write matrix to bitstream */ /* TEMP: use default matrix instead */ FAME_WARNING("Custom quantisation matrix not supported, using default.\n"); *inter_matrix = mpeg1_inter_quantisation_table; } else { *inter_matrix = mpeg1_inter_quantisation_table; } /* fill in intra DC quantizer values */ for(qscale = 0; qscale < 32; qscale++) { /* MPEG-1 uses linear quantization */ intra_dc_y_scale_table[qscale] = 8; intra_dc_c_scale_table[qscale] = 8; } /* MPEG-1 uses local mismatch control */ *mismatch_type = fame_mismatch_local;}static void mpeg1_close(fame_syntax_t *syntax){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); syntax_mpeg1->vlc_table -= 64*255; /* uncenter vlc_table */ fame_free(syntax_mpeg1->vlc_table);}static void mpeg1_use(fame_syntax_t *syntax, unsigned char *buffer, int size){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); bitbuffer_init(&syntax_mpeg1->buffer, buffer, size);}static int mpeg1_flush(fame_syntax_t *syntax){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); return(bitbuffer_flush(&syntax_mpeg1->buffer));}static void mpeg1_start_sequence(fame_syntax_t *syntax, int width, int height, int fps_num, int fps_den, int size, int bitrate){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); int frame_rate = 0; if(fps_num == 60 && fps_den == 1) frame_rate = 8; /* 60 fps */ if(fps_num == 60000 && fps_den == 1001) frame_rate = 7; /* 60000/1001 fps */ if(fps_num == 50 && fps_den == 1) frame_rate = 6; /* 50 fps */ if(fps_num == 30 && fps_den == 1) frame_rate = 5; /* 30 fps */ if(fps_num == 30000 && fps_den == 1001) frame_rate = 4; /* 30000/1001 fps */ if(fps_num == 25 && fps_den == 1) frame_rate = 3; /* 25 fps */ if(fps_num == 24 && fps_den == 1) frame_rate = 2; /* 24 fps */ if(fps_num == 24000 && fps_den == 1001) frame_rate = 1; /* 24000/1001 fps */ if(!frame_rate) { FAME_WARNING("MPEG-1 doesn't support frame rate %d/%d! " "Using 25 fps instead.\n", fps_num, fps_den); fps_num = 25; fps_den = 1; frame_rate = 3; /* 25 fps */ } syntax_mpeg1->fps_num = fps_num; syntax_mpeg1->fps_den = fps_den; /* sequence start code */ bitbuffer_write(&syntax_mpeg1->buffer, SEQUENCE_START_CODE, 32); /* picture size x */ bitbuffer_write(&syntax_mpeg1->buffer, width & 0xfff, 12); /* picture size y */ bitbuffer_write(&syntax_mpeg1->buffer, height & 0xfff, 12); /* pixel aspect ratio */ bitbuffer_write(&syntax_mpeg1->buffer, 1, 4); /* frames per second */ bitbuffer_write(&syntax_mpeg1->buffer, frame_rate, 4); /* bitrate */ bitbuffer_write(&syntax_mpeg1->buffer, (bitrate/50) & 0x3ffff, 18); /* marker */ bitbuffer_write(&syntax_mpeg1->buffer, 1, 1); /* VBV buffer size */ bitbuffer_write(&syntax_mpeg1->buffer, size/2048, 10); /* constrained mode */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1); /* load intra matrix */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1); /* load non-intra matrix */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1);}static void mpeg1_start_GOP(fame_syntax_t *syntax, int frame){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); int fps_num, fps_den; fps_num = syntax_mpeg1->fps_num; fps_den = syntax_mpeg1->fps_den; /* gop start code */ bitbuffer_write(&syntax_mpeg1->buffer, GOP_START_CODE, 32); /* drop frame flag */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1); /* timecount hours */ bitbuffer_write(&syntax_mpeg1->buffer, ((int)(frame*fps_den/(3600*fps_num))) & 0x1f, 5); /* timecount minutes */ bitbuffer_write(&syntax_mpeg1->buffer, (((int)(frame*fps_den/(60*fps_num)))%60) & 0x3f, 6); /* marker */ bitbuffer_write(&syntax_mpeg1->buffer, 1, 1); /* timecount seconds */ bitbuffer_write(&syntax_mpeg1->buffer, (((int)(frame*fps_den/fps_num))%60) & 0x3f, 6); /* timecount frames */ bitbuffer_write(&syntax_mpeg1->buffer, (frame%(fps_num/fps_den+1)) & 0x3f, 6); /* closed GOP */ bitbuffer_write(&syntax_mpeg1->buffer, 1, 1); /* broken link */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1); /* fill out to 8 bytes */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 5);}static void mpeg1_start_picture(fame_syntax_t *syntax, char frame_type, int frame_number, fame_box_t *box, int rounding_control, int search_range){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); /* compute fcode */ if(search_range < 8) syntax_mpeg1->f_code = 1; else if(search_range < 16) syntax_mpeg1->f_code = 2; else if(search_range < 32) syntax_mpeg1->f_code = 3; else if(search_range < 64) syntax_mpeg1->f_code = 4; else if(search_range < 128) syntax_mpeg1->f_code = 5; else if(search_range < 256) syntax_mpeg1->f_code = 6; else syntax_mpeg1->f_code = 7; switch(frame_type) { case 'I': syntax_mpeg1->frame_type = frame_type_I; break; case 'P': syntax_mpeg1->frame_type = frame_type_P; break; default: FAME_ERROR("Unsupported picture coding type %c", frame_type); return; } /* picture start code */ bitbuffer_write(&syntax_mpeg1->buffer, PICT_START_CODE, 32); /* frame number */ bitbuffer_write(&syntax_mpeg1->buffer, frame_number & 0x3ff, 10); /* frame type */ switch(syntax_mpeg1->frame_type) { case frame_type_I: bitbuffer_write(&syntax_mpeg1->buffer, I_FRAME, 3); break; case frame_type_P: bitbuffer_write(&syntax_mpeg1->buffer, P_FRAME, 3); break; } /* vbv delay */ bitbuffer_write(&syntax_mpeg1->buffer, 0xFFFF, 16); /* variable bitrate */ switch(syntax_mpeg1->frame_type) { case frame_type_I: bitbuffer_write(&syntax_mpeg1->buffer, 0, 1); /* end marker */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 2); /* fill out to 8 bytes */ break; case frame_type_P: /* half-pel forward vector */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1); /* forward vector range */ bitbuffer_write(&syntax_mpeg1->buffer, syntax_mpeg1->f_code & 0x7, 3); /* end marker */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1); /* fill out to 8 bytes */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 6); break; }}static void mpeg1_start_slice(fame_syntax_t *syntax, int vpos, int length, unsigned char qscale){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); /* reset the predictors to their original values */ syntax_mpeg1->y_dc_pred = 128; syntax_mpeg1->cr_dc_pred = syntax_mpeg1->cb_dc_pred = 128; syntax_mpeg1->mv_pred.dx = syntax_mpeg1->mv_pred.dy = 0; syntax_mpeg1->slice_start = syntax_mpeg1->prev_mb_addr = vpos * syntax_mpeg1->mb_width - 1; syntax_mpeg1->slice_length = length; syntax_mpeg1->previous_coding = motion_intra; syntax_mpeg1->qscale = qscale; /* new slice starting at vpos */ bitbuffer_write(&syntax_mpeg1->buffer, SLICE_BASE_CODE + vpos, 32); /* quantization scale */ bitbuffer_write(&syntax_mpeg1->buffer, qscale & 31, 5); /* end marker */ bitbuffer_write(&syntax_mpeg1->buffer, 0, 1);}static void mpeg1_end_slice(fame_syntax_t *syntax){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); mpeg1_next_start_code(&syntax_mpeg1->buffer); /* align to byte */}static void mpeg1_end_sequence(fame_syntax_t *syntax){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); /* end sequence code */ bitbuffer_write(&syntax_mpeg1->buffer, SEQUENCE_END_CODE, 32);}static void mpeg1_predict_vector(fame_syntax_t *syntax, int mb_x, int mb_y, int k, fame_motion_vector_t *mv){ fame_syntax_mpeg1_t *syntax_mpeg1 = FAME_SYNTAX_MPEG1(syntax); mv[k].dx = syntax_mpeg1->mv_pred.dx;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -