diff options
-rw-r--r-- | src/libvdpau/h264_parser.c | 122 | ||||
-rw-r--r-- | src/libvdpau/h264_parser.h | 7 | ||||
-rw-r--r-- | src/libvdpau/nal.c | 9 | ||||
-rw-r--r-- | src/libvdpau/vdpau_h264.c | 92 |
4 files changed, 173 insertions, 57 deletions
diff --git a/src/libvdpau/h264_parser.c b/src/libvdpau/h264_parser.c index fcec0b92e..d7e4940ae 100644 --- a/src/libvdpau/h264_parser.c +++ b/src/libvdpau/h264_parser.c @@ -1073,6 +1073,7 @@ struct nal_parser* init_parser() parser->nal1 = init_nal_unit(); parser->current_nal = parser->nal0; parser->last_nal = parser->nal1; + parser->slice_cnt = 1; parser->field = -1; @@ -1091,21 +1092,81 @@ void free_parser(struct nal_parser *parser) free(parser); } -void parse_prebuf() +void parse_codec_private(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len) { + struct buf_reader bufr; + + bufr.buf = inbuf; + bufr.cur_pos = inbuf; + bufr.cur_offset = 8; + bufr.len = inbuf_len; + + struct nal_unit *nal = parser->current_nal; + struct nal_unit *nal1 = parser->last_nal; + + if (!nal->sps) + nal->sps = calloc(1, sizeof(struct seq_parameter_set_rbsp)); + else + memset(nal->sps, 0x00, sizeof(struct seq_parameter_set_rbsp)); + + /* reserved */ + read_bits(&bufr, 8); + nal->sps->profile_idc = read_bits(&bufr, 8); + read_bits(&bufr, 8); + nal->sps->level_idc = read_bits(&bufr, 8); + read_bits(&bufr, 6); + + parser->nal_size_length = read_bits(&bufr, 2) + 1; + read_bits(&bufr, 3); + uint8_t sps_count = read_bits(&bufr, 5); + + inbuf += 6; + inbuf_len -= 6; + int i; + for(i = 0; i < sps_count; i++) { + uint16_t sps_size = read_bits(&bufr, 16); + inbuf += 2; + inbuf_len -= 2; + parse_nal(inbuf, sps_size, parser); + inbuf += sps_size; + inbuf_len -= sps_size; + } + + bufr.buf = inbuf; + bufr.cur_pos = inbuf; + bufr.cur_offset = 8; + bufr.len = inbuf_len; + + uint8_t pps_count = read_bits(&bufr, 8); + inbuf += 1; + for(i = 0; i < pps_count; i++) { + uint16_t pps_size = read_bits(&bufr, 16); + inbuf += 2; + inbuf_len -= 2; + parse_nal(inbuf, pps_size, parser); + inbuf += pps_size; + inbuf_len -= pps_size; + } + copy_nal_unit(nal1, nal); + printf("done parsing extradata\n"); } + int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, uint8_t **ret_buf, uint32_t *ret_len, uint32_t *ret_slice_cnt) { int32_t next_nal = 0; int parsed_len = 0; int search_offset = 0; + int start_seq_len = 3; uint8_t completed_nal = 0; uint8_t *prebuf = parser->prebuf; + if(parser->nal_size_length > 0) + start_seq_len = 4; + if(parser->last_nal_res == 1 && parser->current_nal && parser->current_nal->slc) { int i; @@ -1117,8 +1178,7 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, parser); } } - - while ((next_nal = seek_for_nal(inbuf+search_offset, inbuf_len-parsed_len-search_offset)) >= 0) { + while ((next_nal = seek_for_nal(inbuf+search_offset, inbuf_len-parsed_len-search_offset, parser)) >= 0) { next_nal += search_offset; if(parser->incomplete_nal || completed_nal || next_nal == 0) { @@ -1137,12 +1197,16 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, parsed_len += next_nal; inbuf += next_nal; - parser->last_nal_res = parse_nal(prebuf+3, parser->prebuf_len-3, parser); + parser->last_nal_res = parse_nal(prebuf+start_seq_len, parser->prebuf_len-start_seq_len, parser); if (parser->last_nal_res == 1 && parser->buf_len > 0) { - //printf("Frame complete: %d bytes\n", parser->buf_len); - *ret_buf = malloc(parser->buf_len); - xine_fast_memcpy(*ret_buf, parser->buf, parser->buf_len); - *ret_len = parser->buf_len; + int offset = 0; + if(parser->nal_size_length > 0) + offset = start_seq_len; + + //printf("Frame complete: %d bytes\n", parser->buf_len-offset); + *ret_len = parser->buf_len-offset; + *ret_buf = malloc(*ret_len); + xine_fast_memcpy(*ret_buf, parser->buf+offset, *ret_len); *ret_slice_cnt = parser->slice_cnt; //memset(parser->buf, 0x00, parser->buf_len); @@ -1193,8 +1257,8 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, inbuf += next_nal; } - - search_offset = 3; + if(!parser->nal_size_length) + search_offset = start_seq_len; } /* if inbuf does not end with the start of a new nal @@ -1218,11 +1282,11 @@ int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, * this might happen if the nal start sequence is split * over the buf-boundary - if this is the case we */ - if(parsed_len > 2 && - (next_nal = seek_for_nal(prebuf+3, parser->prebuf_len)) >= 0) { - inbuf -= parser->prebuf_len-next_nal-3; - parsed_len -= parser->prebuf_len-next_nal-3; - parser->prebuf_len = next_nal+3; + if(!parser->nal_size_length && parsed_len > 2 && + (next_nal = seek_for_nal(prebuf+start_seq_len, parser->prebuf_len, parser)) >= 0) { + inbuf -= parser->prebuf_len-next_nal-start_seq_len; + parsed_len -= parser->prebuf_len-next_nal-start_seq_len; + parser->prebuf_len = next_nal+start_seq_len; } } @@ -1361,8 +1425,34 @@ int parse_nal(uint8_t *buf, int buf_len, struct nal_parser *parser) return 0; } -int seek_for_nal(uint8_t *buf, int buf_len) +int seek_for_nal(uint8_t *buf, int buf_len, struct nal_parser *parser) { + if(parser->nal_size_length > 0) { + + if(buf_len <= 0) + return -1; + + int next_nal = parser->next_nal_position; + if(!next_nal) { + struct buf_reader bufr; + + bufr.buf = buf; + bufr.cur_pos = buf; + bufr.cur_offset = 8; + bufr.len = buf_len; + + next_nal = read_bits(&bufr, parser->nal_size_length*8)+4; + } + + if(next_nal > buf_len) { + parser->next_nal_position = next_nal-buf_len; + return -1; + } else + parser->next_nal_position = 0; + + return next_nal; + } + int i; for (i = 0; i < buf_len - 2; i++) { if (buf[i] == 0x00 && buf[i + 1] == 0x00 && buf[i + 2] == 0x01) { diff --git a/src/libvdpau/h264_parser.h b/src/libvdpau/h264_parser.h index e40a9b985..bb9e12f79 100644 --- a/src/libvdpau/h264_parser.h +++ b/src/libvdpau/h264_parser.h @@ -55,6 +55,9 @@ struct nal_parser { uint8_t have_top; uint8_t have_frame; + uint8_t nal_size_length; + uint32_t next_nal_size; + struct nal_unit *nal0; struct nal_unit *nal1; struct nal_unit *current_nal; @@ -75,11 +78,13 @@ struct nal_parser { int parse_nal(uint8_t *buf, int buf_len, struct nal_parser *parser); -int seek_for_nal(uint8_t *buf, int buf_len); +int seek_for_nal(uint8_t *buf, int buf_len, struct nal_parser *parser); struct nal_parser* init_parser(); void free_parser(struct nal_parser *parser); int parse_frame(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len, uint8_t **ret_buf, uint32_t *ret_len, uint32_t *ret_slice_cnt); +void parse_codec_private(struct nal_parser *parser, uint8_t *inbuf, int inbuf_len); + #endif diff --git a/src/libvdpau/nal.c b/src/libvdpau/nal.c index eaa32c700..541699dbd 100644 --- a/src/libvdpau/nal.c +++ b/src/libvdpau/nal.c @@ -66,7 +66,10 @@ void copy_nal_unit(struct nal_unit *dest, struct nal_unit *src) if(!dest->slc) dest->slc = malloc(sizeof(struct slice_header)); - xine_fast_memcpy(dest->sps, src->sps, sizeof(struct seq_parameter_set_rbsp)); - xine_fast_memcpy(dest->pps, src->pps, sizeof(struct pic_parameter_set_rbsp)); - xine_fast_memcpy(dest->slc, src->slc, sizeof(struct slice_header)); + if(src->sps) + xine_fast_memcpy(dest->sps, src->sps, sizeof(struct seq_parameter_set_rbsp)); + if(src->pps) + xine_fast_memcpy(dest->pps, src->pps, sizeof(struct pic_parameter_set_rbsp)); + if(src->slc) + xine_fast_memcpy(dest->slc, src->slc, sizeof(struct slice_header)); } diff --git a/src/libvdpau/vdpau_h264.c b/src/libvdpau/vdpau_h264.c index 7064f7799..971876abd 100644 --- a/src/libvdpau/vdpau_h264.c +++ b/src/libvdpau/vdpau_h264.c @@ -371,16 +371,17 @@ static int vdpau_decoder_init(video_decoder_t *this_gen) return 1; } -static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *vdp_buffer, uint32_t slice_count) +static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *vdp_buffer, uint32_t slice_count, int use_vdp_buffers) { vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *)this_gen; vo_frame_t *img = this->last_img; VdpPictureInfoH264 pic; + fill_vdpau_pictureinfo_h264(this_gen, slice_count, &pic); if(!this->decoder_started && !pic.is_reference) - return; + return 0; this->decoder_started = 1; @@ -406,14 +407,14 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v /*int i; printf("Decode data: \n"); - for(i = 0; i < ((vdp_buffer.bitstream_bytes < 20) ? vdp_buffer.bitstream_bytes : 20); i++) { - printf("%02x ", ((uint8_t*)vdp_buffer.bitstream)[i]); + for(i = 0; i < ((vdp_buffer[use_vdp_buffers-1].bitstream_bytes < 20) ? vdp_buffer[use_vdp_buffers-1].bitstream_bytes : 20); i++) { + printf("%02x ", ((uint8_t*)vdp_buffer[use_vdp_buffers-1].bitstream)[i]); if((i+1) % 10 == 0) printf("\n"); } printf("\n...\n"); - for(i = vdp_buffer.bitstream_bytes - 20; i < vdp_buffer.bitstream_bytes; i++) { - printf("%02x ", ((uint8_t*)vdp_buffer.bitstream)[i]); + for(i = vdp_buffer[use_vdp_buffers-1].bitstream_bytes - 20; i < vdp_buffer[use_vdp_buffers-1].bitstream_bytes; i++) { + printf("%02x ", ((uint8_t*)vdp_buffer[use_vdp_buffers-1].bitstream)[i]); if((i+1) % 10 == 0) printf("\n"); }*/ @@ -444,11 +445,12 @@ static int vdpau_decoder_render(video_decoder_t *this_gen, VdpBitstreamBuffer *v //printf("Decode: NUM: %d, REF: %d, BYTES: %d, PTS: %lld\n", pic.frame_num, pic.is_reference, vdp_buffer.bitstream_bytes, this->curr_pts); VdpStatus status = this->vdpau_accel->vdp_decoder_render(this->decoder, - surface, (VdpPictureInfo*)&pic, 1, vdp_buffer); + surface, (VdpPictureInfo*)&pic, use_vdp_buffers, vdp_buffer); - // FIXME: do we really hit all cases here? - if(((uint8_t*)vdp_buffer->bitstream) != NULL) { - free((uint8_t*)vdp_buffer->bitstream); + /* only free the actual data, as the start seq is only + * locally allocated anyway. */ + if(((uint8_t*)vdp_buffer[use_vdp_buffers-1].bitstream) != NULL) { + free((uint8_t*)vdp_buffer[use_vdp_buffers-1].bitstream); } this->curr_pts = this->next_pts; @@ -540,8 +542,16 @@ static void vdpau_h264_decode_data (video_decoder_t *this_gen, vdpau_h264_decoder_t *this = (vdpau_h264_decoder_t *) this_gen; - VdpBitstreamBuffer vdp_buffer; - vdp_buffer.struct_version = VDP_BITSTREAM_BUFFER_VERSION; + VdpBitstreamBuffer vdp_buffer[2]; + uint8_t start_seq[3] = { 0x00, 0x00, 0x01 }; + vdp_buffer[0].struct_version = vdp_buffer[1].struct_version = VDP_BITSTREAM_BUFFER_VERSION; + int use_vdp_buffers = 1; + + if(this->nal_parser->nal_size_length > 0) { + vdp_buffer[0].bitstream_bytes = 3; + vdp_buffer[0].bitstream = start_seq; + use_vdp_buffers = 2; + } /* a video decoder does not care about this flag (?) */ if (buf->decoder_flags & BUF_FLAG_PREVIEW) @@ -557,37 +567,40 @@ static void vdpau_h264_decode_data (video_decoder_t *this_gen, this->width = bih->biWidth; this->height = bih->biHeight; - } + uint8_t *codec_private = buf->content + sizeof(xine_bmiheader); + uint32_t codec_private_len = bih->biSize - sizeof(xine_bmiheader); - /* parse the first nal packages to retrieve profile type */ - int len = 0; - uint32_t slice_count; + parse_codec_private(this->nal_parser, codec_private, codec_private_len); + } else { + /* parse the first nal packages to retrieve profile type */ + int len = 0; + uint32_t slice_count; - if(buf->pts != 0) - this->next_pts = buf->pts; + if(buf->pts != 0) + this->next_pts = buf->pts; - while(len < buf->size) { - len += parse_frame(this->nal_parser, buf->content + len, buf->size - len, - (void*)&vdp_buffer.bitstream, &vdp_buffer.bitstream_bytes, &slice_count); + while(len < buf->size) { + len += parse_frame(this->nal_parser, buf->content + len, buf->size - len, + (void*)&vdp_buffer[use_vdp_buffers-1].bitstream, &vdp_buffer[use_vdp_buffers-1].bitstream_bytes, &slice_count); - if(this->decoder == VDP_INVALID_HANDLE && - this->nal_parser->current_nal->sps != NULL && - this->nal_parser->current_nal->sps->pic_width > 0 && - this->nal_parser->current_nal->sps->pic_height > 0) { + if(this->decoder == VDP_INVALID_HANDLE && + this->nal_parser->current_nal->sps != NULL && + this->nal_parser->current_nal->sps->pic_width > 0 && + this->nal_parser->current_nal->sps->pic_height > 0) { - vdpau_decoder_init(this_gen); - } + vdpau_decoder_init(this_gen); + } - if(this->decoder != VDP_INVALID_HANDLE && - vdp_buffer.bitstream_bytes > 0 && - this->nal_parser->current_nal->slc != NULL && - this->nal_parser->current_nal->sps != NULL && - this->nal_parser->current_nal->pps != NULL) { - vdpau_decoder_render(this_gen, &vdp_buffer, slice_count); - } + if(this->decoder != VDP_INVALID_HANDLE && + vdp_buffer[use_vdp_buffers-1].bitstream_bytes > 0 && + this->nal_parser->current_nal->slc != NULL && + this->nal_parser->current_nal->sps != NULL && + this->nal_parser->current_nal->pps != NULL) { + vdpau_decoder_render(this_gen, vdp_buffer, slice_count, use_vdp_buffers); + } + } } - } /* @@ -613,9 +626,14 @@ static void vdpau_h264_reset (video_decoder_t *this_gen) { this->decoder = VDP_INVALID_HANDLE; } - free_parser(this->nal_parser); + /* only reset the parser for continous streams + * like ts or pes + */ + if(!this->nal_parser->nal_size_length) { + free_parser(this->nal_parser); + this->nal_parser = init_parser(); + } - this->nal_parser = init_parser(); this->buf = NULL; this->wait_for_bottom_field = 0; this->video_step = 0; |