📄 mpeg_video.c
字号:
/*******************************************************************
MPEG Video Decoding Module
*******************************************************************/
#include <stdio.h>
#include "gop_list.h"
#include "filename.h"
#include "registry.h"
#include "idct_llm_int.h"
#include "idct_llm_mmx.h"
#include "idct_reference.h"
#include "idct_reference_sse.h"
#include "idct_ap922_int.h"
#include "idct_ap922_mmx.h"
#include "idct_ap922_sse.h"
#include "idct_ap922_sse2.h"
#define MPEG_VIDEO_C
#include "mpeg_video.h"
/* grobal */
MPEG_VIDEO *open_mpeg_video(char *path);
int close_mpeg_video(MPEG_VIDEO *p);
OUT_BUFFER_ELEMENT *read_frame(MPEG_VIDEO *in, __int64 frame);
int get_picture_coding_type(MPEG_VIDEO *in, __int64 frame);
/* local */
static OUT_BUFFER_ELEMENT *proc_sequence_header(MPEG_VIDEO *in, __int64 frame);
static OUT_BUFFER_ELEMENT *proc_gop_header(MPEG_VIDEO *in, __int64 frame);
static OUT_BUFFER_ELEMENT *proc_picture_data(MPEG_VIDEO *in, __int64 frame);
static OUT_BUFFER_ELEMENT *store_forward_reference_frame(MPEG_VIDEO *in, __int64 frame);
static OUT_BUFFER_ELEMENT *store_backward_reference_frame(MPEG_VIDEO *in, __int64 frame);
static OUT_BUFFER_ELEMENT *store_current_decoding_frame(MPEG_VIDEO *in, __int64 frame);
static OUT_BUFFER_ELEMENT *rotate_reference_frame(MPEG_VIDEO *in, __int64 frame);
static int is_seek_required(MPEG_VIDEO *p, __int64 frame);
static void sequence_header_to_decode_picture_parameter(SEQUENCE_HEADER *in, DECODE_PICTURE_PARAMETER *out);
static void picture_header_to_decode_picture_parameter(PICTURE_HEADER *in, DECODE_PICTURE_PARAMETER *out);
static void decode_2nd_field(MPEG_VIDEO *p);
static OUT_BUFFER_ELEMENT *add_frame_out_buffer_with_resize(MPEG_VIDEO *p, FRAME *data, OUTPUT_PARAMETER *prm);
static int is_registered_suffix(char *filepath);
static void clear_output_parameters(MPEG_VIDEO *p);
static void setup_m2v_config(M2V_CONFIG *p);
static void setup_chroma_upsampling_function(MPEG_VIDEO *p, int chroma_format, int simd);
static void setup_convert_function(MPEG_VIDEO *p, int chroma_format, int simd);
static void setup_qw_function(DECODE_PICTURE_PARAMETER *p, int simd);
static void setup_idct_function(DECODE_PICTURE_PARAMETER *p, M2V_CONFIG *prm);
static void setup_mc_function(DECODE_PICTURE_PARAMETER *p, M2V_CONFIG *prm);
static void setup_add_block_function(DECODE_PICTURE_PARAMETER *p, M2V_CONFIG *prm);
static void setup_field_order(MPEG_VIDEO *p, M2V_CONFIG *prm);
static void resize_parameter_to_bgr_conversion_parameter(RESIZE_PARAMETER *in, BGR_CONVERSION_PARAMETER *out);
static YUY2_CONVERT select_yuy2_convert_function(int simd);
/******************************************************************************/
MPEG_VIDEO *open_mpeg_video(char *path)
{
int code;
__int64 limit;
GOP g;
READ_GOP_PARAMETER *gp;
GOP_LIST *gl;
MPEG_VIDEO *out;
char gl_path[FILENAME_MAX]; /* GOP LIST file path */
/* initialize */
out = (MPEG_VIDEO *)calloc(1, sizeof(MPEG_VIDEO)+sizeof(DECODE_PICTURE_PARAMETER)+16);
if(out == NULL){
return NULL;
}
code = (int)out;
code += sizeof(MPEG_VIDEO)+15;
code &= 0xfffffff0;
out->dec_prm = (DECODE_PICTURE_PARAMETER *)code;
code = 0;
/* start file check */
if(!is_registered_suffix(path)){
free(out);
return NULL;
}
if(!open_video_stream(path, &(out->bitstream))){
/* can't open */
free(out);
return NULL;
}
limit = get_filecheck_limit();
while(vs_next_start_code(&(out->bitstream))){
code = vs_get_bits(&(out->bitstream), 32);
if(code == 0x1B3){
break;
}else if(limit < video_stream_tell(&(out->bitstream))){
/* limit over */
break;
}
}
if(code != 0x1B3){
/* failed to find sequence_start_code */
close_video_stream(&(out->bitstream));
free(out);
return 0;
}
if(!read_sequence_header(&(out->bitstream), &(out->seq))){
/* has invalid sequence header */
close_video_stream(&(out->bitstream));
free(out);
return 0;
}
sequence_header_to_read_picture_header_option(&(out->seq), &(out->pic_opt));
sequence_header_to_decode_picture_parameter(&(out->seq), out->dec_prm);
while(vs_next_start_code(&(out->bitstream))){
code = vs_get_bits(&(out->bitstream), 32);
if(code == 0x100){
break;
}else if(limit < video_stream_tell(&(out->bitstream))){
/* limit over */
break;
}
}
if(code != 0x100){
/* failed to find picture_start_code */
close_video_stream(&(out->bitstream));
free(out);
return 0;
}
if(!read_picture_header(&(out->bitstream), &(out->pic), &(out->pic_opt))){
/* has invalid picture header */
close_video_stream(&(out->bitstream));
free(out);
return 0;
}
/* finish file check */
setup_m2v_config(&(out->config));
out->orig_field_order = out->pic.pc.top_field_first;
video_stream_seek(&(out->bitstream), 0, SEEK_SET);
gp = new_read_gop_parameter(&(out->bitstream), &(out->seq), &(out->pic_opt), out->orig_field_order);
if(gp == NULL){
/* malloc failed */
close_video_stream(&(out->bitstream));
free(out);
return 0;
}
out->rate = gp->rate;
out->scale = gp->scale;
if( (out->config.gl & M2V_CONFIG_GL_ALWAYS_SCAN) == 0){
if(read_gop(gp, &g)){
/* gop timecode is sequential */
out->fg.arg1 = (void *)gp;
out->fg.func = find_gop_with_timecode;
out->fg.release = delete_read_gop_parameter;
out->total = count_frame(gp);
}
}
if(out->total <= 0){
/* gop timecode is not sequential */
/* or GL_ALWAYS_SCAN selected */
delete_read_gop_parameter(gp);
if(out->config.gl & M2V_CONFIG_GL_NEVER_SAVE){
video_stream_seek(&(out->bitstream), 0, SEEK_SET);
gl = new_gop_list(&(out->bitstream), &(out->pic_opt), out->orig_field_order);
if(gl == NULL){
/* stream has something probrem */
close_video_stream(&(out->bitstream));
return 0;
}
}else{
strcpy(gl_path, path);
cut_suffix(gl_path);
strcat(gl_path, ".gl");
gl = load_gop_list(gl_path);
if( (gl == NULL) || (gl->stream_length != out->bitstream.file_length) ){
video_stream_seek(&(out->bitstream), 0, SEEK_SET);
gl = new_gop_list(&(out->bitstream), &(out->pic_opt), out->orig_field_order);
if(gl == NULL){
/* stream has something probrem */
close_video_stream(&(out->bitstream));
return 0;
}
store_gop_list(gl, gl_path);
}
}
out->fg.arg1 = (void *) gl;
out->fg.func = find_gop_with_gop_list;
out->fg.release = delete_gop_list;
out->total = gl->num_of_frame;
}
sequence_header_to_bgr_conversion_parameter(&(out->seq), &(out->bgr_prm), &(out->config));
if(sequence_header_to_yuy2_conversion_parameter(&(out->seq), &(out->ycc_prm), &(out->config))){
out->yuy2_cc = select_yuy2_convert_function(out->config.simd);
}else{
out->yuy2_cc = yuy2_convert_none;
}
if( (out->seq.has_sequence_extension == 0) || (out->seq.se.progressive) ){
out->config.field_mode = M2V_CONFIG_FRAME_KEEP_ORIGINAL;
}
setup_field_order(out, &(out->config));
setup_idct_function(out->dec_prm, &(out->config));
setup_mc_function(out->dec_prm, &(out->config));
setup_add_block_function(out->dec_prm, &(out->config));
out->rsz_prm = create_resize_parameter(&(out->seq), &(out->config));
resize_parameter_to_bgr_conversion_parameter(out->rsz_prm, &(out->bgr_prm));
if(out->seq.has_sequence_extension){
setup_chroma_upsampling_function(out, out->seq.se.chroma_format, out->config.simd);
setup_convert_function(out, out->seq.se.chroma_format, out->config.simd);
}else{
setup_chroma_upsampling_function(out, 1, out->config.simd);
setup_convert_function(out, 1, out->config.simd);
}
setup_qw_function(out->dec_prm, out->config.simd);
out->width = out->bgr_prm.prm.width;
out->height = out->bgr_prm.prm.height;
video_stream_seek(&(out->bitstream), 0, SEEK_SET);
out->dec_buf.forward = NULL;
out->dec_buf.backward = NULL;
out->dec_buf.current = NULL;
out->current.frame_count = 0;
out->current.start_frame = -1;
clear_output_parameters(out);
InitializeCriticalSection(&(out->lock));
return out;
}
int close_mpeg_video(MPEG_VIDEO *p)
{
if(p == NULL){
return 0;
}
clear_out_buffer(&(p->out_buf));
if(p->dec_buf.forward){
delete_frame(p->dec_buf.forward);
p->dec_buf.forward = NULL;
}
if(p->dec_buf.backward){
delete_frame(p->dec_buf.backward);
p->dec_buf.backward = NULL;
}
if(p->fg.release){
p->fg.release(p->fg.arg1);
}
release_resize_parameter(p->rsz_prm);
close_video_stream(&(p->bitstream));
DeleteCriticalSection(&(p->lock));
free(p);
return 1;
}
OUT_BUFFER_ELEMENT *read_frame(MPEG_VIDEO *in, __int64 frame)
{
int code;
OUT_BUFFER_ELEMENT *r;
EnterCriticalSection(&(in->lock));
r = search_out_buffer(&(in->out_buf), frame);
if(r){
goto READ_FRAME_END;
}
if(is_seek_required(in, frame)){
in->current = in->fg.func(in->fg.arg1, frame);
video_stream_seek(&(in->bitstream), in->current.offset, SEEK_SET);
if(in->dec_buf.forward){
delete_frame(in->dec_buf.forward);
in->dec_buf.forward = NULL;
}
if(in->dec_buf.backward){
delete_frame(in->dec_buf.backward);
in->dec_buf.backward = NULL;
}
if(in->current.frame_count == 0){
goto READ_FRAME_END;
}
if(in->current.start_frame > frame){
goto READ_FRAME_END;
}
clear_output_parameters(in);
clear_out_buffer(&(in->out_buf));
if(in->current.sh){
if( (in->seq.orig_h_size != in->current.sh->orig_h_size) || (in->seq.orig_v_size != in->current.sh->orig_v_size) ){
release_resize_parameter(in->rsz_prm);
in->rsz_prm = create_force_resize_parameter(in->current.sh, in->width, in->height);
}
memcpy(&(in->seq), in->current.sh, sizeof(SEQUENCE_HEADER));
sequence_header_to_bgr_conversion_parameter(&(in->seq), &(in->bgr_prm), &(in->config));
if(sequence_header_to_yuy2_conversion_parameter(&(in->seq), &(in->ycc_prm), &(in->config))){
in->yuy2_cc = select_yuy2_convert_function(in->config.simd);
}else{
in->yuy2_cc = yuy2_convert_none;
}
sequence_header_to_read_picture_header_option(&(in->seq), &(in->pic_opt));
sequence_header_to_decode_picture_parameter(&(in->seq), in->dec_prm);
resize_parameter_to_bgr_conversion_parameter(in->rsz_prm, &(in->bgr_prm));
}
}
while(vs_next_start_code(&(in->bitstream))){
code = vs_get_bits(&(in->bitstream), 32);
if(code == 0x1B3){
r = proc_sequence_header(in, frame);
}else if(code == 0x1B8){
r = proc_gop_header(in, frame);
}else if(code == 0x100){
r = proc_picture_data(in, frame);
}
if(r || (in->bwd_prm.index > frame)){
goto READ_FRAME_END;
}
}
if(in->dec_buf.forward){
r = store_forward_reference_frame(in, frame);
}
if(in->dec_buf.backward){
if(r){
store_backward_reference_frame(in, frame);
}else{
r = store_backward_reference_frame(in, frame);
}
}
in->fwd_prm.index = -1;
in->bwd_prm.index = -1;
READ_FRAME_END:
LeaveCriticalSection(&(in->lock));
return r;
}
int get_picture_coding_type(MPEG_VIDEO *in, __int64 frame)
{
int r;
OUT_BUFFER_ELEMENT *e;
e = read_frame(in, frame);
if(e == NULL){
return 0;
}
r = e->prm.picture_coding_type;
if( (r == 3) && e->prm.closed_gop ){
r = 4;
}
return r;
}
static OUT_BUFFER_ELEMENT *proc_sequence_header(MPEG_VIDEO *in, __int64 frame)
{
int width, height;
OUT_BUFFER_ELEMENT *fwd;
OUT_BUFFER_ELEMENT *bwd;
width = in->seq.orig_h_size;
height = in->seq.orig_v_size;
fwd = bwd = NULL;
read_sequence_header(&(in->bitstream), &(in->seq));
if( (width != in->seq.orig_h_size) || (height != in->seq.orig_v_size) ){
if(in->dec_buf.forward){
fwd = store_forward_reference_frame(in, frame);
}
if(in->dec_buf.backward){
bwd = store_backward_reference_frame(in, frame);
}
release_resize_parameter(in->rsz_prm);
in->rsz_prm = create_force_resize_parameter(&(in->seq), in->width, in->height);
}
sequence_header_to_bgr_conversion_parameter(&(in->seq), &(in->bgr_prm), &(in->config));
if(sequence_header_to_yuy2_conversion_parameter(&(in->seq), &(in->ycc_prm), &(in->config))){
in->yuy2_cc = select_yuy2_convert_function(in->config.simd);
}else{
in->yuy2_cc = yuy2_convert_none;
}
sequence_header_to_read_picture_header_option(&(in->seq), &(in->pic_opt));
sequence_header_to_decode_picture_parameter(&(in->seq), in->dec_prm);
resize_parameter_to_bgr_conversion_parameter(in->rsz_prm, &(in->bgr_prm));
if(fwd){
return fwd;
}
return bwd;
}
static OUT_BUFFER_ELEMENT *proc_gop_header(MPEG_VIDEO *in, __int64 frame)
{
OUT_BUFFER_ELEMENT *fwd;
OUT_BUFFER_ELEMENT *bwd;
fwd = bwd = NULL;
vs_erase_bits(&(in->bitstream), 25); /* erase timecode */
in->closed_gop = vs_get_bits(&(in->bitstream), 1);
if(vs_get_bits(&(in->bitstream), 1)){ /* broken link */
if(in->dec_buf.forward){
fwd = store_forward_reference_frame(in, frame);
}
if(in->dec_buf.backward){
bwd = store_backward_reference_frame(in, frame);
}
}
if(fwd){
return fwd;
}
return bwd;
}
static OUT_BUFFER_ELEMENT *proc_picture_data(MPEG_VIDEO *in, __int64 frame)
{
OUT_BUFFER_ELEMENT *r;
r = NULL;
read_picture_header(&(in->bitstream), &(in->pic), &(in->pic_opt));
picture_header_to_decode_picture_parameter(&(in->pic), in->dec_prm);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -