summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libvdpau/h264_parser.c122
-rw-r--r--src/libvdpau/h264_parser.h7
-rw-r--r--src/libvdpau/nal.c9
-rw-r--r--src/libvdpau/vdpau_h264.c92
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;