/***************************************************************************** * picture.c: libvlc API picture management ***************************************************************************** * Copyright (C) 2018 VLC authors and VideoLAN * * Authors: Hugo Beauzée-Luyssen * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "libvlc_internal.h" #include #include #include #include #include #include #include "picture_internal.h" struct libvlc_picture_t { vlc_atomic_rc_t rc; libvlc_picture_type_t type; block_t* converted; video_format_t fmt; libvlc_time_t time; input_attachment_t* attachment; }; struct libvlc_picture_list_t { size_t count; libvlc_picture_t* pictures[]; }; libvlc_picture_t* libvlc_picture_new( vlc_object_t* p_obj, picture_t* input, libvlc_picture_type_t type, unsigned int width, unsigned int height, bool crop ) { libvlc_picture_t *pic = malloc( sizeof( *pic ) ); if ( unlikely( pic == NULL ) ) return NULL; vlc_atomic_rc_init( &pic->rc ); pic->type = type; pic->time = libvlc_time_from_vlc_tick( input->date ); pic->attachment = NULL; static const vlc_fourcc_t table[] = { [libvlc_picture_Jpg] = VLC_CODEC_JPEG, [libvlc_picture_Png] = VLC_CODEC_PNG, [libvlc_picture_Argb] = VLC_CODEC_ARGB, [libvlc_picture_WebP] = VLC_CODEC_WEBP, }; assert(ARRAY_SIZE(table) > type && table[type] != 0); vlc_fourcc_t format = table[type]; if ( picture_Export( p_obj, &pic->converted, &pic->fmt, input, format, width, height, crop ) != VLC_SUCCESS ) { free( pic ); return NULL; } return pic; } static void libvlc_picture_block_release( block_t* block ) { free( block ); } static const struct vlc_block_callbacks block_cbs = { libvlc_picture_block_release, }; static bool IsSupportedByLibVLC(vlc_fourcc_t fcc) { switch (fcc) { case VLC_CODEC_PNG: case VLC_CODEC_JPEG: case VLC_CODEC_WEBP: return true; default: return false; } } static libvlc_picture_t* libvlc_picture_from_attachment( input_attachment_t* attachment ) { vlc_fourcc_t fcc = image_Mime2Fourcc( attachment->psz_mime ); if (!IsSupportedByLibVLC(fcc)) return NULL; libvlc_picture_t *pic = malloc( sizeof( *pic ) ); if ( unlikely( pic == NULL ) ) return NULL; pic->converted = block_New(&block_cbs, attachment->p_data, attachment->i_data); if ( unlikely( pic->converted == NULL ) ) { free(pic); return NULL; } vlc_atomic_rc_init( &pic->rc ); pic->attachment = vlc_input_attachment_Hold( attachment ); pic->time = VLC_TICK_INVALID; video_format_Init( &pic->fmt, 0 ); switch ( fcc ) { case VLC_CODEC_PNG: pic->type = libvlc_picture_Png; break; case VLC_CODEC_JPEG: pic->type = libvlc_picture_Jpg; break; case VLC_CODEC_WEBP: pic->type = libvlc_picture_WebP; break; default: vlc_assert_unreachable(); } return pic; } libvlc_picture_t *libvlc_picture_retain( libvlc_picture_t* pic ) { vlc_atomic_rc_inc( &pic->rc ); return pic; } void libvlc_picture_release( libvlc_picture_t* pic ) { if ( vlc_atomic_rc_dec( &pic->rc ) == false ) return; video_format_Clean( &pic->fmt ); if ( pic->converted ) block_Release( pic->converted ); if ( pic->attachment ) vlc_input_attachment_Release( pic->attachment ); free( pic ); } int libvlc_picture_save( const libvlc_picture_t* pic, const char* path ) { FILE* file = vlc_fopen( path, "wb" ); if ( !file ) return -1; size_t res = fwrite( pic->converted->p_buffer, pic->converted->i_buffer, 1, file ); fclose( file ); return res == 1 ? 0 : -1; } const unsigned char* libvlc_picture_get_buffer( const libvlc_picture_t* pic, size_t *size ) { assert( size != NULL ); *size = pic->converted->i_buffer; return pic->converted->p_buffer; } libvlc_picture_type_t libvlc_picture_type( const libvlc_picture_t* pic ) { return pic->type; } unsigned int libvlc_picture_get_stride( const libvlc_picture_t *pic ) { assert( pic->type == libvlc_picture_Argb ); return pic->fmt.i_width * 4; } unsigned int libvlc_picture_get_width( const libvlc_picture_t* pic ) { return pic->fmt.i_visible_width; } unsigned int libvlc_picture_get_height( const libvlc_picture_t* pic ) { return pic->fmt.i_visible_height; } libvlc_time_t libvlc_picture_get_time( const libvlc_picture_t* pic ) { return pic->time; } libvlc_picture_list_t* libvlc_picture_list_from_attachments( input_attachment_t* const* attachments, size_t nb_attachments ) { size_t size = 0; libvlc_picture_list_t* list; if (ckd_mul(&size, nb_attachments, sizeof (libvlc_picture_t *)) || ckd_add(&size, sizeof (*list), size)) return NULL; list = malloc( size ); if ( !list ) return NULL; list->count = 0; for ( size_t i = 0; i < nb_attachments; ++i ) { input_attachment_t* a = attachments[i]; libvlc_picture_t *pic = libvlc_picture_from_attachment( a ); if( !pic ) continue; list->pictures[list->count] = pic; list->count++; } return list; } size_t libvlc_picture_list_count( const libvlc_picture_list_t* list ) { assert( list ); return list->count; } libvlc_picture_t* libvlc_picture_list_at( const libvlc_picture_list_t* list, size_t index ) { assert( list ); return list->pictures[index]; } void libvlc_picture_list_destroy( libvlc_picture_list_t* list ) { if ( !list ) return; for ( size_t i = 0; i < list->count; ++i ) libvlc_picture_release( list->pictures[i] ); free( list ); }