static int DecodeVideo( decoder_t *p_dec, block_t *p_block ) { if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; picture_t *p_pic = DecodeBlock( p_dec, p_block ); if( p_pic != NULL ) decoder_QueueVideo( p_dec, p_pic ); return VLCDEC_SUCCESS; }
/***************************************************************************** * DecodeFrame: decodes a video frame. *****************************************************************************/ static int DecodeFrame( decoder_t *p_dec, block_t *p_block ) { if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; p_block = DecodeBlock( p_dec, p_block ); if( p_block == NULL ) return VLCDEC_SUCCESS; decoder_sys_t *p_sys = p_dec->p_sys; /* Get a new picture */ picture_t *p_pic = NULL; if( !decoder_UpdateVideoFormat( p_dec ) ) p_pic = decoder_NewPicture( p_dec ); if( p_pic == NULL ) { block_Release( p_block ); return VLCDEC_SUCCESS; } FillPicture( p_dec, p_block, p_pic ); /* Date management: 1 frame per packet */ p_pic->date = date_Get( &p_dec->p_sys->pts ); date_Increment( &p_sys->pts, 1 ); if( p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK ) { p_pic->b_progressive = false; p_pic->i_nb_fields = (p_block->i_flags & BLOCK_FLAG_SINGLE_FIELD) ? 1 : 2; if( p_block->i_flags & BLOCK_FLAG_TOP_FIELD_FIRST ) p_pic->b_top_field_first = true; else p_pic->b_top_field_first = false; } else p_pic->b_progressive = true; block_Release( p_block ); decoder_QueueVideo( p_dec, p_pic ); return VLCDEC_SUCCESS; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with a complete image. ****************************************************************************/ static int DecodeBlock( decoder_t *p_dec, block_t *p_block ) { decoder_sys_t *p_sys = (decoder_sys_t *) p_dec->p_sys; picture_t *p_pic = NULL; int32_t i_width, i_height; RsvgHandle *rsvg = NULL; cairo_surface_t *surface = NULL; cairo_t *cr = NULL; if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; if( p_block->i_flags & BLOCK_FLAG_CORRUPTED) { block_Release( p_block ); return VLCDEC_SUCCESS; } rsvg = rsvg_handle_new_from_data( p_block->p_buffer, p_block->i_buffer, NULL ); if( !rsvg ) goto done; RsvgDimensionData dim; rsvg_handle_get_dimensions( rsvg, &dim ); if( p_sys->f_scale > 0.0 ) { i_width = (int32_t)(p_sys->f_scale * dim.width); i_height = (int32_t)(p_sys->f_scale * dim.height); } else { /* Keep aspect */ if( p_sys->i_width < 0 && p_sys->i_height > 0 ) { i_width = dim.width * p_sys->i_height / dim.height; i_height = p_sys->i_height; } else if( p_sys->i_width > 0 && p_sys->i_height < 0 ) { i_width = p_sys->i_width; i_height = dim.height * p_sys->i_width / dim.height; } else if( p_sys->i_width > 0 && p_sys->i_height > 0 ) { i_width = dim.width * p_sys->i_height / dim.height; i_height = p_sys->i_height; } else { i_width = dim.width; i_height = dim.height; } } p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma = VLC_CODEC_BGRA; p_dec->fmt_out.video.i_width = i_width; p_dec->fmt_out.video.i_height = i_height; p_dec->fmt_out.video.i_visible_width = i_width; p_dec->fmt_out.video.i_visible_height = i_height; p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; p_dec->fmt_out.video.i_rmask = 0x80800000; /* Since librsvg v1.0 */ p_dec->fmt_out.video.i_gmask = 0x0000ff00; p_dec->fmt_out.video.i_bmask = 0x000000ff; video_format_FixRgb(&p_dec->fmt_out.video); /* Get a new picture */ if( decoder_UpdateVideoFormat( p_dec ) ) goto done; p_pic = decoder_NewPicture( p_dec ); if( !p_pic ) goto done; /* NOTE: Do not use the stride calculation from cairo, because it is wrong: * stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, dim.width); * Use the stride from VLC its picture_t::p[0].i_pitch, which is correct. */ memset(p_pic->p[0].p_pixels, 0, p_pic->p[0].i_pitch * p_pic->p[0].i_lines); surface = cairo_image_surface_create_for_data( p_pic->p->p_pixels, CAIRO_FORMAT_ARGB32, i_width, i_height, p_pic->p[0].i_pitch ); if( !surface ) { picture_Release( p_pic ); p_pic = NULL; goto done; } /* Decode picture */ cr = cairo_create( surface ); if( !cr ) { picture_Release( p_pic ); p_pic = NULL; goto done; } if ( i_width != dim.width || i_height != dim.height ) { double sw, sh; if ( p_sys->f_scale > 0.0 && !(p_sys->i_width > 0 || p_sys->i_height > 0) ) sw = sh = p_sys->f_scale; else { double aspect = (double) (dim.width * p_dec->fmt_out.video.i_sar_num) / (dim.height * p_dec->fmt_out.video.i_sar_den); sw = aspect * i_width / dim.width; sh = aspect * i_height / dim.height; } cairo_scale(cr, sw, sh); } if( !rsvg_handle_render_cairo( rsvg, cr ) ) { picture_Release( p_pic ); p_pic = NULL; goto done; } p_pic->date = p_block->i_pts != VLC_TICK_INVALID ? p_block->i_pts : p_block->i_dts; done: if( rsvg ) g_object_unref( G_OBJECT( rsvg ) ); if( cr ) cairo_destroy( cr ); if( surface ) cairo_surface_destroy( surface ); block_Release( p_block ); if( p_pic != NULL ) decoder_QueueVideo( p_dec, p_pic ); return VLCDEC_SUCCESS; }
static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id) { decoder_sys_t *p_sys = p_dec->p_sys; HRESULT hr; picture_t *picture = NULL; block_t *aout_buffer = NULL; DWORD output_status = 0; MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample, 0, NULL }; hr = IMFTransform_ProcessOutput(p_sys->mft, 0, 1, &output_buffer, &output_status); if (output_buffer.pEvents) IMFCollection_Release(output_buffer.pEvents); /* Use the returned sample since it can be provided by the MFT. */ IMFSample *output_sample = output_buffer.pSample; if (hr == S_OK) { if (!output_sample) return VLC_SUCCESS; LONGLONG sample_time; hr = IMFSample_GetSampleTime(output_sample, &sample_time); if (FAILED(hr)) goto error; /* Convert from 100 nanoseconds unit to microseconds. */ sample_time /= 10; DWORD total_length = 0; hr = IMFSample_GetTotalLength(output_sample, &total_length); if (FAILED(hr)) goto error; if (p_dec->fmt_in.i_cat == VIDEO_ES) { if (decoder_UpdateVideoFormat(p_dec)) return VLC_SUCCESS; picture = decoder_NewPicture(p_dec); if (!picture) return VLC_SUCCESS; UINT32 interlaced = false; hr = IMFSample_GetUINT32(output_sample, &MFSampleExtension_Interlaced, &interlaced); picture->b_progressive = !interlaced; picture->date = sample_time; } else { if (decoder_UpdateAudioFormat(p_dec)) goto error; if (p_dec->fmt_out.audio.i_bitspersample == 0 || p_dec->fmt_out.audio.i_channels == 0) goto error; int samples = total_length / (p_dec->fmt_out.audio.i_bitspersample * p_dec->fmt_out.audio.i_channels / 8); aout_buffer = decoder_NewAudioBuffer(p_dec, samples); if (!aout_buffer) return VLC_SUCCESS; if (aout_buffer->i_buffer < total_length) goto error; aout_buffer->i_pts = sample_time; } IMFMediaBuffer *output_media_buffer = NULL; hr = IMFSample_GetBufferByIndex(output_sample, 0, &output_media_buffer); BYTE *buffer_start; hr = IMFMediaBuffer_Lock(output_media_buffer, &buffer_start, NULL, NULL); if (FAILED(hr)) goto error; if (p_dec->fmt_in.i_cat == VIDEO_ES) CopyPackedBufferToPicture(picture, buffer_start); else memcpy(aout_buffer->p_buffer, buffer_start, total_length); hr = IMFMediaBuffer_Unlock(output_media_buffer); IMFSample_Release(output_media_buffer); if (FAILED(hr)) goto error; if (p_sys->output_sample) { /* Sample is not provided by the MFT: clear its content. */ hr = IMFMediaBuffer_SetCurrentLength(output_media_buffer, 0); if (FAILED(hr)) goto error; } else { /* Sample is provided by the MFT: decrease refcount. */ IMFSample_Release(output_sample); } } else if (hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_TYPE_NOT_SET) { if (p_sys->output_type) IMFMediaType_Release(p_sys->output_type); if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type)) goto error; /* Reallocate output sample. */ if (p_sys->output_sample) IMFSample_Release(p_sys->output_sample); p_sys->output_sample = NULL; if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample)) goto error; return VLC_SUCCESS; } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { return VLC_SUCCESS; } else /* An error not listed above occurred */ { msg_Err(p_dec, "Unexpected error in IMFTransform::ProcessOutput: %#lx", hr); goto error; } if (p_dec->fmt_in.i_cat == VIDEO_ES) decoder_QueueVideo(p_dec, picture); else decoder_QueueAudio(p_dec, aout_buffer); return VLC_SUCCESS; error: msg_Err(p_dec, "Error in ProcessOutputStream()"); if (picture) picture_Release(picture); if (aout_buffer) block_Release(aout_buffer); return VLC_EGENERIC; }
static int Decode (decoder_t *dec, block_t *block) { picture_t *pic = NULL; if (block == NULL) /* No Drain */ return VLCDEC_SUCCESS; if (block->i_pts <= VLC_TS_INVALID) goto drop; /* undated block, should never happen */ if (block->i_buffer < sz_XWDheader) goto drop; /* Skip XWD header */ const XWDFileHeader *hdr = (const void *)block->p_buffer; uint32_t hdrlen = ntohl(hdr->header_size); if (hdrlen < sz_XWDheader || ntohl(hdr->file_version) < XWD_FILE_VERSION || ntohl(hdr->pixmap_format) != 2 /* ZPixmap */) goto drop; hdrlen += ntohl(hdr->ncolors) * sz_XWDColor; if (hdrlen > block->i_buffer) goto drop; block->p_buffer += hdrlen; block->i_buffer -= hdrlen; /* Parse XWD header */ vlc_fourcc_t chroma = 0; switch (ntohl(hdr->pixmap_depth)) { case 8: if (ntohl(hdr->bits_per_pixel) == 8) chroma = VLC_CODEC_RGB8; break; case 15: if (ntohl(hdr->bits_per_pixel) == 16) chroma = VLC_CODEC_RGB15; break; case 16: if (ntohl(hdr->bits_per_pixel) == 16) chroma = VLC_CODEC_RGB16; break; case 24: switch (ntohl(hdr->bits_per_pixel)) { case 32: chroma = VLC_CODEC_RGB32; break; case 24: chroma = VLC_CODEC_RGB24; break; } break; case 32: if (ntohl(hdr->bits_per_pixel) == 32) chroma = VLC_CODEC_ARGB; break; } /* TODO: check image endianess, set RGB mask */ if (!chroma) goto drop; video_format_Setup(&dec->fmt_out.video, chroma, ntohl(hdr->pixmap_width), ntohl(hdr->pixmap_height), ntohl(hdr->pixmap_width), ntohl(hdr->pixmap_height), dec->fmt_in.video.i_sar_num, dec->fmt_in.video.i_sar_den); const size_t copy = dec->fmt_out.video.i_width * (dec->fmt_out.video.i_bits_per_pixel / 8); const uint32_t pitch = ntohl(hdr->bytes_per_line); /* Build picture */ if (pitch < copy || (block->i_buffer / pitch) < dec->fmt_out.video.i_height) goto drop; if (decoder_UpdateVideoFormat(dec)) goto drop; pic = decoder_NewPicture(dec); if (pic == NULL) goto drop; const uint8_t *in = block->p_buffer; uint8_t *out = pic->p->p_pixels; for (unsigned i = 0; i < dec->fmt_out.video.i_height; i++) { memcpy(out, in, copy); in += pitch; out += pic->p->i_pitch; } pic->date = block->i_pts; pic->b_progressive = true; drop: block_Release(block); decoder_QueueVideo(dec, pic); return VLCDEC_SUCCESS; }
/* * This function must be fed with a complete compressed frame. */ static int DecodeBlock(decoder_t *p_dec, block_t *p_block) { decoder_sys_t *p_sys = p_dec->p_sys; picture_t *p_pic = 0; JSAMPARRAY p_row_pointers = NULL; if (!p_block) /* No Drain */ return VLCDEC_SUCCESS; if (p_block->i_flags & BLOCK_FLAG_CORRUPTED ) { block_Release(p_block); return VLCDEC_SUCCESS; } /* libjpeg longjmp's there in case of error */ if (setjmp(p_sys->setjmp_buffer)) { goto error; } jpeg_create_decompress(&p_sys->p_jpeg); jpeg_mem_src(&p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer); jpeg_save_markers( &p_sys->p_jpeg, EXIF_JPEG_MARKER, 0xffff ); jpeg_read_header(&p_sys->p_jpeg, TRUE); p_sys->p_jpeg.out_color_space = JCS_RGB; jpeg_start_decompress(&p_sys->p_jpeg); /* Set output properties */ p_dec->fmt_out.i_codec = VLC_CODEC_RGB24; p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width = p_sys->p_jpeg.output_width; p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height = p_sys->p_jpeg.output_height; p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; int i_otag; /* Orientation tag has valid range of 1-8. 1 is normal orientation, 0 = unspecified = normal */ i_otag = jpeg_GetOrientation( &p_sys->p_jpeg ); if ( i_otag > 1 ) { msg_Dbg( p_dec, "Jpeg orientation is %d", i_otag ); p_dec->fmt_out.video.orientation = ORIENT_FROM_EXIF( i_otag ); } jpeg_GetProjection(&p_sys->p_jpeg, &p_dec->fmt_out.video); /* Get a new picture */ if (decoder_UpdateVideoFormat(p_dec)) { goto error; } p_pic = decoder_NewPicture(p_dec); if (!p_pic) { goto error; } /* Decode picture */ p_row_pointers = malloc(sizeof(JSAMPROW) * p_sys->p_jpeg.output_height); if (!p_row_pointers) { goto error; } for (unsigned i = 0; i < p_sys->p_jpeg.output_height; i++) { p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i; } while (p_sys->p_jpeg.output_scanline < p_sys->p_jpeg.output_height) { jpeg_read_scanlines(&p_sys->p_jpeg, p_row_pointers + p_sys->p_jpeg.output_scanline, p_sys->p_jpeg.output_height - p_sys->p_jpeg.output_scanline); } jpeg_finish_decompress(&p_sys->p_jpeg); jpeg_destroy_decompress(&p_sys->p_jpeg); free(p_row_pointers); p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts; block_Release(p_block); decoder_QueueVideo( p_dec, p_pic ); return VLCDEC_SUCCESS; error: jpeg_destroy_decompress(&p_sys->p_jpeg); free(p_row_pointers); block_Release(p_block); return VLCDEC_SUCCESS; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with a complete compressed frame. ****************************************************************************/ static int DecodeBlock( decoder_t *p_dec, block_t *p_block ) { decoder_sys_t *p_sys = p_dec->p_sys; picture_t *p_pic = NULL; SDL_Surface *p_surface; SDL_RWops *p_rw; if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) { block_Release( p_block ); return VLCDEC_SUCCESS; } p_rw = SDL_RWFromConstMem( p_block->p_buffer, p_block->i_buffer ); /* Decode picture. */ p_surface = IMG_LoadTyped_RW( p_rw, 1, (char*)p_sys->psz_sdl_type ); if ( p_surface == NULL ) { msg_Warn( p_dec, "SDL_image couldn't load the image (%s)", IMG_GetError() ); goto error; } switch ( p_surface->format->BitsPerPixel ) { case 16: p_dec->fmt_out.i_codec = VLC_CODEC_RGB16; break; case 8: case 24: p_dec->fmt_out.i_codec = VLC_CODEC_RGB24; break; case 32: p_dec->fmt_out.i_codec = VLC_CODEC_RGB32; break; default: msg_Warn( p_dec, "unknown bits/pixel format (%d)", p_surface->format->BitsPerPixel ); goto error; } p_dec->fmt_out.video.i_width = p_surface->w; p_dec->fmt_out.video.i_height = p_surface->h; p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; /* Get a new picture. */ if( decoder_UpdateVideoFormat( p_dec ) ) goto error; p_pic = decoder_NewPicture( p_dec ); if ( p_pic == NULL ) goto error; switch ( p_surface->format->BitsPerPixel ) { case 8: { for ( int i = 0; i < p_surface->h; i++ ) { uint8_t *p_src = (uint8_t*)p_surface->pixels + i * p_surface->pitch; uint8_t *p_dst = p_pic->p[0].p_pixels + i * p_pic->p[0].i_pitch; for ( int j = 0; j < p_surface->w; j++ ) { uint8_t r, g, b; SDL_GetRGB( *(p_src++), p_surface->format, &r, &g, &b ); *(p_dst++) = r; *(p_dst++) = g; *(p_dst++) = b; } } break; } case 16: { uint8_t *p_src = p_surface->pixels; uint8_t *p_dst = p_pic->p[0].p_pixels; int i_pitch = p_pic->p[0].i_pitch < p_surface->pitch ? p_pic->p[0].i_pitch : p_surface->pitch; for ( int i = 0; i < p_surface->h; i++ ) { memcpy( p_dst, p_src, i_pitch ); p_src += p_surface->pitch; p_dst += p_pic->p[0].i_pitch; } break; } case 24: { for ( int i = 0; i < p_surface->h; i++ ) { uint8_t *p_src = (uint8_t*)p_surface->pixels + i * p_surface->pitch; uint8_t *p_dst = p_pic->p[0].p_pixels + i * p_pic->p[0].i_pitch; for ( int j = 0; j < p_surface->w; j++ ) { uint8_t r, g, b; SDL_GetRGB( *(uint32_t*)p_src, p_surface->format, &r, &g, &b ); *(p_dst++) = r; *(p_dst++) = g; *(p_dst++) = b; p_src += 3; } } break; } case 32: { for ( int i = 0; i < p_surface->h; i++ ) { uint8_t *p_src = (uint8_t*)p_surface->pixels + i * p_surface->pitch; uint8_t *p_dst = p_pic->p[0].p_pixels + i * p_pic->p[0].i_pitch; for ( int j = 0; j < p_surface->w; j++ ) { uint8_t r, g, b, a; SDL_GetRGBA( *(uint32_t*)p_src, p_surface->format, &r, &g, &b, &a ); *(p_dst++) = b; *(p_dst++) = g; *(p_dst++) = r; *(p_dst++) = a; p_src += 4; } } break; } } p_pic->date = (p_block->i_pts != VLC_TICK_INVALID) ? p_block->i_pts : p_block->i_dts; decoder_QueueVideo( p_dec, p_pic ); error: if ( p_surface != NULL ) SDL_FreeSurface( p_surface ); block_Release( p_block ); return VLCDEC_SUCCESS; }