diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/parser.c b/src/add-ons/media/plugins/avcodec/libavcodec/parser.c index 027e0b9bf8..94399bfbbe 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/parser.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/parser.c @@ -3,26 +3,32 @@ * Copyright (c) 2003 Fabrice Bellard. * Copyright (c) 2003 Michael Niedermayer. * - * This library is free software; you can redistribute it and/or + * This file is part of FFmpeg. + * + * FFmpeg 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 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * FFmpeg 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "avcodec.h" -#include "mpegvideo.h" -#include "mpegaudio.h" + +#include "parser.h" AVCodecParser *av_first_parser = NULL; +AVCodecParser* av_parser_next(AVCodecParser *p){ + if(p) return p->next; + else return av_first_parser; +} + void av_register_codec_parser(AVCodecParser *parser) { parser->next = av_first_parser; @@ -35,10 +41,15 @@ AVCodecParserContext *av_parser_init(int codec_id) AVCodecParser *parser; int ret; + if(codec_id == CODEC_ID_NONE) + return NULL; + for(parser = av_first_parser; parser != NULL; parser = parser->next) { if (parser->codec_ids[0] == codec_id || parser->codec_ids[1] == codec_id || - parser->codec_ids[2] == codec_id) + parser->codec_ids[2] == codec_id || + parser->codec_ids[3] == codec_id || + parser->codec_ids[4] == codec_id) goto found; } return NULL; @@ -60,64 +71,97 @@ AVCodecParserContext *av_parser_init(int codec_id) return NULL; } } + s->fetch_timestamp=1; + s->pict_type = FF_I_TYPE; return s; } -/* NOTE: buf_size == 0 is used to signal EOF so that the last frame - can be returned if necessary */ -int av_parser_parse(AVCodecParserContext *s, +void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove){ + int i; + + s->dts= s->pts= AV_NOPTS_VALUE; + s->offset= 0; + for(i = 0; i < AV_PARSER_PTS_NB; i++) { + if ( s->next_frame_offset + off >= s->cur_frame_offset[i] + &&(s-> frame_offset < s->cur_frame_offset[i] || !s->frame_offset) + //check is disabled becausue mpeg-ts doesnt send complete PES packets + && /*s->next_frame_offset + off <*/ s->cur_frame_end[i]){ + s->dts= s->cur_frame_dts[i]; + s->pts= s->cur_frame_pts[i]; + s->offset = s->next_frame_offset - s->cur_frame_offset[i]; + if(remove) + s->cur_frame_offset[i]= INT64_MAX; + } + } +} + +/** + * + * @param buf input + * @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output) + * @param pts input presentation timestamp + * @param dts input decoding timestamp + * @param poutbuf will contain a pointer to the first byte of the output frame + * @param poutbuf_size will contain the length of the output frame + * @return the number of bytes of the input bitstream used + * + * Example: + * @code + * while(in_len){ + * len = av_parser_parse(myparser, AVCodecContext, &data, &size, + * in_data, in_len, + * pts, dts); + * in_data += len; + * in_len -= len; + * + * if(size) + * decode_frame(data, size); + * } + * @endcode + */ +int av_parser_parse(AVCodecParserContext *s, AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, + uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int64_t pts, int64_t dts) { - int index, i, k; + int index, i; uint8_t dummy_buf[FF_INPUT_BUFFER_PADDING_SIZE]; - + if (buf_size == 0) { /* padding is always necessary even if EOF, so we add it here */ memset(dummy_buf, 0, sizeof(dummy_buf)); buf = dummy_buf; } else { /* add a new packet descriptor */ - k = (s->cur_frame_start_index + 1) & (AV_PARSER_PTS_NB - 1); - s->cur_frame_start_index = k; - s->cur_frame_offset[k] = s->cur_offset; - s->cur_frame_pts[k] = pts; - s->cur_frame_dts[k] = dts; - - /* fill first PTS/DTS */ - if (s->cur_offset == 0) { - s->last_pts = pts; - s->last_dts = dts; + if(pts != AV_NOPTS_VALUE || dts != AV_NOPTS_VALUE){ + i = (s->cur_frame_start_index + 1) & (AV_PARSER_PTS_NB - 1); + s->cur_frame_start_index = i; + s->cur_frame_offset[i] = s->cur_offset; + s->cur_frame_end[i] = s->cur_offset + buf_size; + s->cur_frame_pts[i] = pts; + s->cur_frame_dts[i] = dts; } } + if (s->fetch_timestamp){ + s->fetch_timestamp=0; + s->last_pts = s->pts; + s->last_dts = s->dts; + ff_fetch_timestamp(s, 0, 0); + } + /* WARNING: the returned index can be negative */ - index = s->parser->parser_parse(s, avctx, poutbuf, poutbuf_size, buf, buf_size); + index = s->parser->parser_parse(s, avctx, (const uint8_t **)poutbuf, poutbuf_size, buf, buf_size); +//av_log(NULL, AV_LOG_DEBUG, "parser: in:%"PRId64", %"PRId64", out:%"PRId64", %"PRId64", in:%d out:%d id:%d\n", pts, dts, s->last_pts, s->last_dts, buf_size, *poutbuf_size, avctx->codec_id); /* update the file pointer */ if (*poutbuf_size) { /* fill the data for the current frame */ - s->frame_offset = s->last_frame_offset; - s->pts = s->last_pts; - s->dts = s->last_dts; - + s->frame_offset = s->next_frame_offset; + /* offset of the next frame */ - s->last_frame_offset = s->cur_offset + index; - /* find the packet in which the new frame starts. It - is tricky because of MPEG video start codes - which can begin in one packet and finish in - another packet. In the worst case, an MPEG - video start code could be in 4 different - packets. */ - k = s->cur_frame_start_index; - for(i = 0; i < AV_PARSER_PTS_NB; i++) { - if (s->last_frame_offset >= s->cur_frame_offset[k]) - break; - k = (k - 1) & (AV_PARSER_PTS_NB - 1); - } - s->last_pts = s->cur_frame_pts[k]; - s->last_dts = s->cur_frame_dts[k]; + s->next_frame_offset = s->cur_offset + index; + s->fetch_timestamp=1; } if (index < 0) index = 0; @@ -125,49 +169,61 @@ int av_parser_parse(AVCodecParserContext *s, return index; } +/** + * + * @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed + * @deprecated use AVBitstreamFilter + */ +int av_parser_change(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe){ + + if(s && s->parser->split){ + if((avctx->flags & CODEC_FLAG_GLOBAL_HEADER) || (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER)){ + int i= s->parser->split(avctx, buf, buf_size); + buf += i; + buf_size -= i; + } + } + + /* cast to avoid warning about discarding qualifiers */ + *poutbuf= (uint8_t *) buf; + *poutbuf_size= buf_size; + if(avctx->extradata){ + if( (keyframe && (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER)) + /*||(s->pict_type != FF_I_TYPE && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_NOKEY))*/ + /*||(? && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_BEGIN)*/){ + int size= buf_size + avctx->extradata_size; + *poutbuf_size= size; + *poutbuf= av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + + memcpy(*poutbuf, avctx->extradata, avctx->extradata_size); + memcpy((*poutbuf) + avctx->extradata_size, buf, buf_size + FF_INPUT_BUFFER_PADDING_SIZE); + return 1; + } + } + + return 0; +} + void av_parser_close(AVCodecParserContext *s) { - if (s->parser->parser_close) - s->parser->parser_close(s); - av_free(s->priv_data); - av_free(s); + if(s){ + if (s->parser->parser_close) + s->parser->parser_close(s); + av_free(s->priv_data); + av_free(s); + } } /*****************************************************/ -//#define END_NOT_FOUND (-100) - -#define PICTURE_START_CODE 0x00000100 -#define SEQ_START_CODE 0x000001b3 -#define EXT_START_CODE 0x000001b5 -#define SLICE_MIN_START_CODE 0x00000101 -#define SLICE_MAX_START_CODE 0x000001af - -typedef struct ParseContext1{ - uint8_t *buffer; - int index; - int last_index; - int buffer_size; - uint32_t state; ///< contains the last few bytes in MSB order - int frame_start_found; - int overread; ///< the number of bytes which where irreversibly read from the next frame - int overread_index; ///< the index into ParseContext1.buffer of the overreaded bytes - - /* MPEG2 specific */ - int frame_rate; - int progressive_sequence; - int width, height; - - /* XXX: suppress that, needed by MPEG4 */ - MpegEncContext *enc; - int first_picture; -} ParseContext1; - /** * combines the (truncated) bitstream to a complete frame - * @returns -1 if no complete frame could be created + * @returns -1 if no complete frame could be created, AVERROR(ENOMEM) if there was a memory allocation error */ -static int ff_combine_frame1(ParseContext1 *pc, int next, uint8_t **buf, int *buf_size) +int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_size) { #if 0 if(pc->overread){ @@ -176,17 +232,25 @@ static int ff_combine_frame1(ParseContext1 *pc, int next, uint8_t **buf, int *bu } #endif - /* copy overreaded bytes from last frame into buffer */ + /* Copy overread bytes from last frame into buffer. */ for(; pc->overread>0; pc->overread--){ pc->buffer[pc->index++]= pc->buffer[pc->overread_index++]; } - + + /* flush remaining if EOF */ + if(!*buf_size && next == END_NOT_FOUND){ + next= 0; + } + pc->last_index= pc->index; /* copy into buffer end return */ if(next == END_NOT_FOUND){ - pc->buffer= av_fast_realloc(pc->buffer, &pc->buffer_size, (*buf_size) + pc->index + FF_INPUT_BUFFER_PADDING_SIZE); + void* new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, (*buf_size) + pc->index + FF_INPUT_BUFFER_PADDING_SIZE); + if(!new_buffer) + return AVERROR(ENOMEM); + pc->buffer = new_buffer; memcpy(&pc->buffer[pc->index], *buf, *buf_size); pc->index += *buf_size; return -1; @@ -194,11 +258,14 @@ static int ff_combine_frame1(ParseContext1 *pc, int next, uint8_t **buf, int *bu *buf_size= pc->overread_index= pc->index + next; - + /* append to buffer */ if(pc->index){ - pc->buffer= av_fast_realloc(pc->buffer, &pc->buffer_size, next + pc->index + FF_INPUT_BUFFER_PADDING_SIZE); + void* new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, next + pc->index + FF_INPUT_BUFFER_PADDING_SIZE); + if(!new_buffer) + return AVERROR(ENOMEM); + pc->buffer = new_buffer; memcpy(&pc->buffer[pc->index], *buf, next + FF_INPUT_BUFFER_PADDING_SIZE ); pc->index = 0; *buf= pc->buffer; @@ -220,737 +287,33 @@ static int ff_combine_frame1(ParseContext1 *pc, int next, uint8_t **buf, int *bu return 0; } -/** - * finds the end of the current frame in the bitstream. - * @return the position of the first byte of the next frame, or -1 - */ -static int mpeg1_find_frame_end(ParseContext1 *pc, const uint8_t *buf, int buf_size) +void ff_parse_close(AVCodecParserContext *s) { - int i; - uint32_t state; - - state= pc->state; - - i=0; - if(!pc->frame_start_found){ - for(i=0; i= SLICE_MIN_START_CODE && state <= SLICE_MAX_START_CODE){ - i++; - pc->frame_start_found=1; - break; - } - } - } - - if(pc->frame_start_found){ - /* EOF considered as end of frame */ - if (buf_size == 0) - return 0; - for(; i SLICE_MAX_START_CODE){ - pc->frame_start_found=0; - pc->state=-1; - return i-3; - } - } - } - } - pc->state= state; - return END_NOT_FOUND; -} - -static int find_start_code(const uint8_t **pbuf_ptr, const uint8_t *buf_end) -{ - const uint8_t *buf_ptr; - unsigned int state=0xFFFFFFFF, v; - int val; - - buf_ptr = *pbuf_ptr; - while (buf_ptr < buf_end) { - v = *buf_ptr++; - if (state == 0x000001) { - state = ((state << 8) | v) & 0xffffff; - val = state; - goto found; - } - state = ((state << 8) | v) & 0xffffff; - } - val = -1; - found: - *pbuf_ptr = buf_ptr; - return val; -} - -/* XXX: merge with libavcodec ? */ -#define MPEG1_FRAME_RATE_BASE 1001 - -static const int frame_rate_tab[16] = { - 0, - 24000, - 24024, - 25025, - 30000, - 30030, - 50050, - 60000, - 60060, - // Xing's 15fps: (9) - 15015, - // libmpeg3's "Unofficial economy rates": (10-13) - 5005, - 10010, - 12012, - 15015, - // random, just to avoid segfault !never encode these - 25025, - 25025, -}; - -static void mpegvideo_extract_headers(AVCodecParserContext *s, - AVCodecContext *avctx, - const uint8_t *buf, int buf_size) -{ - ParseContext1 *pc = s->priv_data; - const uint8_t *buf_end; - int32_t start_code; - int frame_rate_index, ext_type, bytes_left; - int frame_rate_ext_n, frame_rate_ext_d; - int top_field_first, repeat_first_field, progressive_frame; - int horiz_size_ext, vert_size_ext; - - s->repeat_pict = 0; - buf_end = buf + buf_size; - while (buf < buf_end) { - start_code = find_start_code(&buf, buf_end); - bytes_left = buf_end - buf; - switch(start_code) { - case PICTURE_START_CODE: - if (bytes_left >= 2) { - s->pict_type = (buf[1] >> 3) & 7; - } - break; - case SEQ_START_CODE: - if (bytes_left >= 4) { - pc->width = avctx->width = (buf[0] << 4) | (buf[1] >> 4); - pc->height = avctx->height = ((buf[1] & 0x0f) << 8) | buf[2]; - frame_rate_index = buf[3] & 0xf; - pc->frame_rate = avctx->frame_rate = frame_rate_tab[frame_rate_index]; - avctx->frame_rate_base = MPEG1_FRAME_RATE_BASE; - avctx->codec_id = CODEC_ID_MPEG1VIDEO; - avctx->sub_id = 1; - } - break; - case EXT_START_CODE: - if (bytes_left >= 1) { - ext_type = (buf[0] >> 4); - switch(ext_type) { - case 0x1: /* sequence extension */ - if (bytes_left >= 6) { - horiz_size_ext = ((buf[1] & 1) << 1) | (buf[2] >> 7); - vert_size_ext = (buf[2] >> 5) & 3; - frame_rate_ext_n = (buf[5] >> 5) & 3; - frame_rate_ext_d = (buf[5] & 0x1f); - pc->progressive_sequence = buf[1] & (1 << 3); - - avctx->width = pc->width | (horiz_size_ext << 12); - avctx->height = pc->height | (vert_size_ext << 12); - avctx->frame_rate = pc->frame_rate * (frame_rate_ext_n + 1); - avctx->frame_rate_base = MPEG1_FRAME_RATE_BASE * (frame_rate_ext_d + 1); - avctx->codec_id = CODEC_ID_MPEG2VIDEO; - avctx->sub_id = 2; /* forces MPEG2 */ - } - break; - case 0x8: /* picture coding extension */ - if (bytes_left >= 5) { - top_field_first = buf[3] & (1 << 7); - repeat_first_field = buf[3] & (1 << 1); - progressive_frame = buf[4] & (1 << 7); - - /* check if we must repeat the frame */ - if (repeat_first_field) { - if (pc->progressive_sequence) { - if (top_field_first) - s->repeat_pict = 4; - else - s->repeat_pict = 2; - } else if (progressive_frame) { - s->repeat_pict = 1; - } - } - } - break; - } - } - break; - case -1: - goto the_end; - default: - /* we stop parsing when we encounter a slice. It ensures - that this function takes a negligible amount of time */ - if (start_code >= SLICE_MIN_START_CODE && - start_code <= SLICE_MAX_START_CODE) - goto the_end; - break; - } - } - the_end: ; -} - -static int mpegvideo_parse(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size) -{ - ParseContext1 *pc = s->priv_data; - int next; - - next= mpeg1_find_frame_end(pc, buf, buf_size); - - if (ff_combine_frame1(pc, next, (uint8_t **)&buf, &buf_size) < 0) { - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; - } - /* we have a full frame : we just parse the first few MPEG headers - to have the full timing information. The time take by this - function should be negligible for uncorrupted streams */ - mpegvideo_extract_headers(s, avctx, buf, buf_size); -#if 0 - printf("pict_type=%d frame_rate=%0.3f repeat_pict=%d\n", - s->pict_type, (double)avctx->frame_rate / avctx->frame_rate_base, s->repeat_pict); -#endif - - *poutbuf = (uint8_t *)buf; - *poutbuf_size = buf_size; - return next; -} - -static void mpegvideo_parse_close(AVCodecParserContext *s) -{ - ParseContext1 *pc = s->priv_data; + ParseContext *pc = s->priv_data; av_free(pc->buffer); - av_free(pc->enc); +} + +void ff_parse1_close(AVCodecParserContext *s) +{ + ParseContext1 *pc1 = s->priv_data; + + av_free(pc1->pc.buffer); + av_free(pc1->enc); } /*************************/ -/** - * finds the end of the current frame in the bitstream. - * @return the position of the first byte of the next frame, or -1 - */ -static int mpeg4_find_frame_end(ParseContext1 *pc, - const uint8_t *buf, int buf_size) -{ - int vop_found, i; - uint32_t state; - - vop_found= pc->frame_start_found; - state= pc->state; - - i=0; - if(!vop_found){ - for(i=0; iframe_start_found=0; - pc->state=-1; - return i-3; - } - } - } - pc->frame_start_found= vop_found; - pc->state= state; - return END_NOT_FOUND; -} - -/* used by parser */ -/* XXX: make it use less memory */ -static int av_mpeg4_decode_header(AVCodecParserContext *s1, - AVCodecContext *avctx, - const uint8_t *buf, int buf_size) -{ - ParseContext1 *pc = s1->priv_data; - MpegEncContext *s = pc->enc; - GetBitContext gb1, *gb = &gb1; - int ret; - - s->avctx = avctx; - s->current_picture_ptr = &s->current_picture; - - if (avctx->extradata_size && pc->first_picture){ - init_get_bits(gb, avctx->extradata, avctx->extradata_size*8); - ret = ff_mpeg4_decode_picture_header(s, gb); - } - - init_get_bits(gb, buf, 8 * buf_size); - ret = ff_mpeg4_decode_picture_header(s, gb); - if (s->width) { - avctx->width = s->width; - avctx->height = s->height; - } - pc->first_picture = 0; - return ret; -} - -int mpeg4video_parse_init(AVCodecParserContext *s) -{ - ParseContext1 *pc = s->priv_data; - - pc->enc = av_mallocz(sizeof(MpegEncContext)); - if (!pc->enc) - return -1; - pc->first_picture = 1; - return 0; -} - -static int mpeg4video_parse(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, +int ff_mpeg4video_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size) -{ - ParseContext1 *pc = s->priv_data; - int next; - - next= mpeg4_find_frame_end(pc, buf, buf_size); - - if (ff_combine_frame1(pc, next, (uint8_t **)&buf, &buf_size) < 0) { - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; - } - av_mpeg4_decode_header(s, avctx, buf, buf_size); - - *poutbuf = (uint8_t *)buf; - *poutbuf_size = buf_size; - return next; -} - -/*************************/ - -static int h263_find_frame_end(ParseContext1 *pc, const uint8_t *buf, int buf_size) -{ - int vop_found, i; - uint32_t state; - - vop_found= pc->frame_start_found; - state= pc->state; - - i=0; - if(!vop_found){ - for(i=0; i>(32-22) == 0x20){ - i++; - vop_found=1; - break; - } - } - } - - if(vop_found){ - for(; i>(32-22) == 0x20){ - pc->frame_start_found=0; - pc->state=-1; - return i-3; - } - } - } - pc->frame_start_found= vop_found; - pc->state= state; - - return END_NOT_FOUND; -} - -static int h263_parse(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size) -{ - ParseContext1 *pc = s->priv_data; - int next; - - next= h263_find_frame_end(pc, buf, buf_size); - - if (ff_combine_frame1(pc, next, (uint8_t **)&buf, &buf_size) < 0) { - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; - } - - *poutbuf = (uint8_t *)buf; - *poutbuf_size = buf_size; - return next; -} - -/*************************/ - -/** - * finds the end of the current frame in the bitstream. - * @return the position of the first byte of the next frame, or -1 - */ -static int h264_find_frame_end(ParseContext1 *pc, const uint8_t *buf, int buf_size) { int i; - uint32_t state; -//printf("first %02X%02X%02X%02X\n", buf[0], buf[1],buf[2],buf[3]); -// mb_addr= pc->mb_addr - 1; - state= pc->state; - //FIXME this will fail with slices + uint32_t state= -1; + for(i=0; iframe_start_found){ - pc->state=-1; - pc->frame_start_found= 0; - return i-3; - } - pc->frame_start_found= 1; - } + if(state == 0x1B3 || state == 0x1B6) + return i-3; } - - pc->state= state; - return END_NOT_FOUND; -} - -static int h264_parse(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size) -{ - ParseContext1 *pc = s->priv_data; - int next; - - next= h264_find_frame_end(pc, buf, buf_size); - - if (ff_combine_frame1(pc, next, (uint8_t **)&buf, &buf_size) < 0) { - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size; - } - - *poutbuf = (uint8_t *)buf; - *poutbuf_size = buf_size; - return next; -} - -/*************************/ - -typedef struct MpegAudioParseContext { - uint8_t inbuf[MPA_MAX_CODED_FRAME_SIZE]; /* input buffer */ - uint8_t *inbuf_ptr; - int frame_size; - int free_format_frame_size; - int free_format_next_header; -} MpegAudioParseContext; - -#define MPA_HEADER_SIZE 4 - -/* header + layer + bitrate + freq + lsf/mpeg25 */ -#define SAME_HEADER_MASK \ - (0xffe00000 | (3 << 17) | (0xf << 12) | (3 << 10) | (3 << 19)) - -static int mpegaudio_parse_init(AVCodecParserContext *s1) -{ - MpegAudioParseContext *s = s1->priv_data; - s->inbuf_ptr = s->inbuf; return 0; } - -static int mpegaudio_parse(AVCodecParserContext *s1, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size) -{ - MpegAudioParseContext *s = s1->priv_data; - int len, ret; - uint32_t header; - const uint8_t *buf_ptr; - - *poutbuf = NULL; - *poutbuf_size = 0; - buf_ptr = buf; - while (buf_size > 0) { - len = s->inbuf_ptr - s->inbuf; - if (s->frame_size == 0) { - /* special case for next header for first frame in free - format case (XXX: find a simpler method) */ - if (s->free_format_next_header != 0) { - s->inbuf[0] = s->free_format_next_header >> 24; - s->inbuf[1] = s->free_format_next_header >> 16; - s->inbuf[2] = s->free_format_next_header >> 8; - s->inbuf[3] = s->free_format_next_header; - s->inbuf_ptr = s->inbuf + 4; - s->free_format_next_header = 0; - goto got_header; - } - /* no header seen : find one. We need at least MPA_HEADER_SIZE - bytes to parse it */ - len = MPA_HEADER_SIZE - len; - if (len > buf_size) - len = buf_size; - if (len > 0) { - memcpy(s->inbuf_ptr, buf_ptr, len); - buf_ptr += len; - buf_size -= len; - s->inbuf_ptr += len; - } - if ((s->inbuf_ptr - s->inbuf) >= MPA_HEADER_SIZE) { - got_header: - header = (s->inbuf[0] << 24) | (s->inbuf[1] << 16) | - (s->inbuf[2] << 8) | s->inbuf[3]; - - ret = mpa_decode_header(avctx, header); - if (ret < 0) { - /* no sync found : move by one byte (inefficient, but simple!) */ - memmove(s->inbuf, s->inbuf + 1, s->inbuf_ptr - s->inbuf - 1); - s->inbuf_ptr--; - dprintf("skip %x\n", header); - /* reset free format frame size to give a chance - to get a new bitrate */ - s->free_format_frame_size = 0; - } else { - s->frame_size = ret; -#if 0 - /* free format: prepare to compute frame size */ - if (decode_header(s, header) == 1) { - s->frame_size = -1; - } -#endif - } - } - } else -#if 0 - if (s->frame_size == -1) { - /* free format : find next sync to compute frame size */ - len = MPA_MAX_CODED_FRAME_SIZE - len; - if (len > buf_size) - len = buf_size; - if (len == 0) { - /* frame too long: resync */ - s->frame_size = 0; - memmove(s->inbuf, s->inbuf + 1, s->inbuf_ptr - s->inbuf - 1); - s->inbuf_ptr--; - } else { - uint8_t *p, *pend; - uint32_t header1; - int padding; - - memcpy(s->inbuf_ptr, buf_ptr, len); - /* check for header */ - p = s->inbuf_ptr - 3; - pend = s->inbuf_ptr + len - 4; - while (p <= pend) { - header = (p[0] << 24) | (p[1] << 16) | - (p[2] << 8) | p[3]; - header1 = (s->inbuf[0] << 24) | (s->inbuf[1] << 16) | - (s->inbuf[2] << 8) | s->inbuf[3]; - /* check with high probability that we have a - valid header */ - if ((header & SAME_HEADER_MASK) == - (header1 & SAME_HEADER_MASK)) { - /* header found: update pointers */ - len = (p + 4) - s->inbuf_ptr; - buf_ptr += len; - buf_size -= len; - s->inbuf_ptr = p; - /* compute frame size */ - s->free_format_next_header = header; - s->free_format_frame_size = s->inbuf_ptr - s->inbuf; - padding = (header1 >> 9) & 1; - if (s->layer == 1) - s->free_format_frame_size -= padding * 4; - else - s->free_format_frame_size -= padding; - dprintf("free frame size=%d padding=%d\n", - s->free_format_frame_size, padding); - decode_header(s, header1); - goto next_data; - } - p++; - } - /* not found: simply increase pointers */ - buf_ptr += len; - s->inbuf_ptr += len; - buf_size -= len; - } - } else -#endif - if (len < s->frame_size) { - if (s->frame_size > MPA_MAX_CODED_FRAME_SIZE) - s->frame_size = MPA_MAX_CODED_FRAME_SIZE; - len = s->frame_size - len; - if (len > buf_size) - len = buf_size; - memcpy(s->inbuf_ptr, buf_ptr, len); - buf_ptr += len; - s->inbuf_ptr += len; - buf_size -= len; - } - // next_data: - if (s->frame_size > 0 && - (s->inbuf_ptr - s->inbuf) >= s->frame_size) { - *poutbuf = s->inbuf; - *poutbuf_size = s->inbuf_ptr - s->inbuf; - s->inbuf_ptr = s->inbuf; - s->frame_size = 0; - break; - } - } - return buf_ptr - buf; -} - -#ifdef CONFIG_AC3 -extern int a52_syncinfo (const uint8_t * buf, int * flags, - int * sample_rate, int * bit_rate); - -typedef struct AC3ParseContext { - uint8_t inbuf[4096]; /* input buffer */ - uint8_t *inbuf_ptr; - int frame_size; - int flags; -} AC3ParseContext; - -#define AC3_HEADER_SIZE 7 -#define A52_LFE 16 - -static int ac3_parse_init(AVCodecParserContext *s1) -{ - AC3ParseContext *s = s1->priv_data; - s->inbuf_ptr = s->inbuf; - return 0; -} - -static int ac3_parse(AVCodecParserContext *s1, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size) -{ - AC3ParseContext *s = s1->priv_data; - const uint8_t *buf_ptr; - int len, sample_rate, bit_rate; - static const int ac3_channels[8] = { - 2, 1, 2, 3, 3, 4, 4, 5 - }; - - *poutbuf = NULL; - *poutbuf_size = 0; - - buf_ptr = buf; - while (buf_size > 0) { - len = s->inbuf_ptr - s->inbuf; - if (s->frame_size == 0) { - /* no header seen : find one. We need at least 7 bytes to parse it */ - len = AC3_HEADER_SIZE - len; - if (len > buf_size) - len = buf_size; - memcpy(s->inbuf_ptr, buf_ptr, len); - buf_ptr += len; - s->inbuf_ptr += len; - buf_size -= len; - if ((s->inbuf_ptr - s->inbuf) == AC3_HEADER_SIZE) { - len = a52_syncinfo(s->inbuf, &s->flags, &sample_rate, &bit_rate); - if (len == 0) { - /* no sync found : move by one byte (inefficient, but simple!) */ - memmove(s->inbuf, s->inbuf + 1, AC3_HEADER_SIZE - 1); - s->inbuf_ptr--; - } else { - s->frame_size = len; - /* update codec info */ - avctx->sample_rate = sample_rate; - avctx->channels = ac3_channels[s->flags & 7]; - if (s->flags & A52_LFE) - avctx->channels++; - avctx->bit_rate = bit_rate; - avctx->frame_size = 6 * 256; - } - } - } else if (len < s->frame_size) { - len = s->frame_size - len; - if (len > buf_size) - len = buf_size; - - memcpy(s->inbuf_ptr, buf_ptr, len); - buf_ptr += len; - s->inbuf_ptr += len; - buf_size -= len; - } else { - *poutbuf = s->inbuf; - *poutbuf_size = s->frame_size; - s->inbuf_ptr = s->inbuf; - s->frame_size = 0; - break; - } - } - return buf_ptr - buf; -} -#endif - -AVCodecParser mpegvideo_parser = { - { CODEC_ID_MPEG1VIDEO, CODEC_ID_MPEG2VIDEO }, - sizeof(ParseContext1), - NULL, - mpegvideo_parse, - mpegvideo_parse_close, -}; - -AVCodecParser mpeg4video_parser = { - { CODEC_ID_MPEG4 }, - sizeof(ParseContext1), - mpeg4video_parse_init, - mpeg4video_parse, - mpegvideo_parse_close, -}; - -AVCodecParser h263_parser = { - { CODEC_ID_H263 }, - sizeof(ParseContext1), - NULL, - h263_parse, - mpegvideo_parse_close, -}; - -AVCodecParser h264_parser = { - { CODEC_ID_H264 }, - sizeof(ParseContext1), - NULL, - h264_parse, - mpegvideo_parse_close, -}; - -AVCodecParser mpegaudio_parser = { - { CODEC_ID_MP2, CODEC_ID_MP3 }, - sizeof(MpegAudioParseContext), - mpegaudio_parse_init, - mpegaudio_parse, - NULL, -}; - -#ifdef CONFIG_AC3 -AVCodecParser ac3_parser = { - { CODEC_ID_AC3 }, - sizeof(AC3ParseContext), - ac3_parse_init, - ac3_parse, - NULL, -}; -#endif diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/parser.h b/src/add-ons/media/plugins/avcodec/libavcodec/parser.h new file mode 100644 index 0000000000..80ee6894e0 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/parser.h @@ -0,0 +1,69 @@ +/* + * AVCodecParser prototypes and definitions + * Copyright (c) 2003 Fabrice Bellard. + * Copyright (c) 2003 Michael Niedermayer. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FFMPEG_PARSER_H +#define FFMPEG_PARSER_H + +#include "avcodec.h" + +typedef struct ParseContext{ + uint8_t *buffer; + int index; + int last_index; + unsigned int buffer_size; + uint32_t state; ///< contains the last few bytes in MSB order + int frame_start_found; + int overread; ///< the number of bytes which where irreversibly read from the next frame + int overread_index; ///< the index into ParseContext.buffer of the overread bytes +} ParseContext; + +struct MpegEncContext; + +typedef struct ParseContext1{ + ParseContext pc; +/* XXX/FIXME PC1 vs. PC */ + /* MPEG-2-specific */ + AVRational frame_rate; + int progressive_sequence; + int width, height; + + /* XXX: suppress that, needed by MPEG-4 */ + struct MpegEncContext *enc; + int first_picture; +} ParseContext1; + +#define END_NOT_FOUND (-100) + +int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_size); +int ff_mpeg4video_split(AVCodecContext *avctx, const uint8_t *buf, + int buf_size); +void ff_parse_close(AVCodecParserContext *s); +void ff_parse1_close(AVCodecParserContext *s); + +/** + * Fetches timestamps for a specific byte within the current access unit. + * @param off byte position within the access unit + * @param remove Found timestamps will be removed if set to 1, kept if set to 0. + */ +void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove); + +#endif /* FFMPEG_PARSER_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pcm.c b/src/add-ons/media/plugins/avcodec/libavcodec/pcm.c index a6c0d343b0..1e822e4498 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/pcm.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pcm.c @@ -2,84 +2,87 @@ * PCM codecs * Copyright (c) 2001 Fabrice Bellard. * - * This library is free software; you can redistribute it and/or + * This file is part of FFmpeg. + * + * FFmpeg 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 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * FFmpeg 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - + /** * @file pcm.c * PCM codecs */ - + #include "avcodec.h" +#include "bitstream.h" // for ff_reverse +#include "bytestream.h" + +#define MAX_CHANNELS 64 /* from g711.c by SUN microsystems (unrestricted use) */ -#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ -#define QUANT_MASK (0xf) /* Quantization field mask. */ -#define NSEGS (8) /* Number of A-law segments. */ -#define SEG_SHIFT (4) /* Left shift for segment number. */ -#define SEG_MASK (0x70) /* Segment field mask. */ +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ -#define BIAS (0x84) /* Bias for linear code. */ +#define BIAS (0x84) /* Bias for linear code. */ /* * alaw2linear() - Convert an A-law value to 16-bit linear PCM * */ -static int alaw2linear(unsigned char a_val) +static av_cold int alaw2linear(unsigned char a_val) { - int t; - int seg; + int t; + int seg; - a_val ^= 0x55; + a_val ^= 0x55; - t = a_val & QUANT_MASK; - seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; - if(seg) t= (t + t + 1 + 32) << (seg + 2); - else t= (t + t + 1 ) << 3; + t = a_val & QUANT_MASK; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + if(seg) t= (t + t + 1 + 32) << (seg + 2); + else t= (t + t + 1 ) << 3; - return ((a_val & SIGN_BIT) ? t : -t); + return (a_val & SIGN_BIT) ? t : -t; } -static int ulaw2linear(unsigned char u_val) +static av_cold int ulaw2linear(unsigned char u_val) { - int t; + int t; - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & QUANT_MASK) << 3) + BIAS; - t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; - return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); + return (u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS); } /* 16384 entries per table */ -static uint8_t *linear_to_alaw = NULL; -static int linear_to_alaw_ref = 0; +static uint8_t linear_to_alaw[16384]; +static uint8_t linear_to_ulaw[16384]; -static uint8_t *linear_to_ulaw = NULL; -static int linear_to_ulaw_ref = 0; - -static void build_xlaw_table(uint8_t *linear_to_xlaw, +static av_cold void build_xlaw_table(uint8_t *linear_to_xlaw, int (*xlaw2linear)(unsigned char), - int mask) + int mask) { int i, j, v, v1, v2; @@ -101,141 +104,168 @@ static void build_xlaw_table(uint8_t *linear_to_xlaw, linear_to_xlaw[0] = linear_to_xlaw[1]; } -static int pcm_encode_init(AVCodecContext *avctx) +static av_cold int pcm_encode_init(AVCodecContext *avctx) { avctx->frame_size = 1; switch(avctx->codec->id) { case CODEC_ID_PCM_ALAW: - if (linear_to_alaw_ref == 0) { - linear_to_alaw = av_malloc(16384); - if (!linear_to_alaw) - return -1; - build_xlaw_table(linear_to_alaw, alaw2linear, 0xd5); - } - linear_to_alaw_ref++; + build_xlaw_table(linear_to_alaw, alaw2linear, 0xd5); break; case CODEC_ID_PCM_MULAW: - if (linear_to_ulaw_ref == 0) { - linear_to_ulaw = av_malloc(16384); - if (!linear_to_ulaw) - return -1; - build_xlaw_table(linear_to_ulaw, ulaw2linear, 0xff); - } - linear_to_ulaw_ref++; + build_xlaw_table(linear_to_ulaw, ulaw2linear, 0xff); break; default: break; } - + + avctx->block_align = avctx->channels * av_get_bits_per_sample(avctx->codec->id)/8; avctx->coded_frame= avcodec_alloc_frame(); avctx->coded_frame->key_frame= 1; - + return 0; } -static int pcm_encode_close(AVCodecContext *avctx) +static av_cold int pcm_encode_close(AVCodecContext *avctx) { av_freep(&avctx->coded_frame); - switch(avctx->codec->id) { - case CODEC_ID_PCM_ALAW: - if (--linear_to_alaw_ref == 0) - av_free(linear_to_alaw); - break; - case CODEC_ID_PCM_MULAW: - if (--linear_to_ulaw_ref == 0) - av_free(linear_to_ulaw); - break; - default: - /* nothing to free */ - break; - } return 0; } +/** + * Write PCM samples macro + * @param type Datatype of native machine format + * @param endian bytestream_put_xxx() suffix + * @param src Source pointer (variable name) + * @param dst Destination pointer (variable name) + * @param n Total number of samples (variable name) + * @param shift Bitshift (bits) + * @param offset Sample value offset + */ +#define ENCODE(type, endian, src, dst, n, shift, offset) \ + samples_##type = (type*)src; \ + for(;n>0;n--) { \ + register type v = (*samples_##type++ >> shift) + offset; \ + bytestream_put_##endian(&dst, v); \ + } + static int pcm_encode_frame(AVCodecContext *avctx, - unsigned char *frame, int buf_size, void *data) + unsigned char *frame, int buf_size, void *data) { int n, sample_size, v; short *samples; unsigned char *dst; + uint8_t *srcu8; + int16_t *samples_int16_t; + int32_t *samples_int32_t; + int64_t *samples_int64_t; + uint16_t *samples_uint16_t; + uint32_t *samples_uint32_t; - switch(avctx->codec->id) { - case CODEC_ID_PCM_S16LE: - case CODEC_ID_PCM_S16BE: - case CODEC_ID_PCM_U16LE: - case CODEC_ID_PCM_U16BE: - sample_size = 2; - break; - default: - sample_size = 1; - break; - } + sample_size = av_get_bits_per_sample(avctx->codec->id)/8; n = buf_size / sample_size; samples = data; dst = frame; + if (avctx->sample_fmt!=avctx->codec->sample_fmts[0]) { + av_log(avctx, AV_LOG_ERROR, "invalid sample_fmt\n"); + return -1; + } + switch(avctx->codec->id) { - case CODEC_ID_PCM_S16LE: - for(;n>0;n--) { - v = *samples++; - dst[0] = v & 0xff; - dst[1] = v >> 8; - dst += 2; - } + case CODEC_ID_PCM_U32LE: + ENCODE(uint32_t, le32, samples, dst, n, 0, 0x80000000) break; - case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_U32BE: + ENCODE(uint32_t, be32, samples, dst, n, 0, 0x80000000) + break; + case CODEC_ID_PCM_S24LE: + ENCODE(int32_t, le24, samples, dst, n, 8, 0) + break; + case CODEC_ID_PCM_S24BE: + ENCODE(int32_t, be24, samples, dst, n, 8, 0) + break; + case CODEC_ID_PCM_U24LE: + ENCODE(uint32_t, le24, samples, dst, n, 8, 0x800000) + break; + case CODEC_ID_PCM_U24BE: + ENCODE(uint32_t, be24, samples, dst, n, 8, 0x800000) + break; + case CODEC_ID_PCM_S24DAUD: for(;n>0;n--) { - v = *samples++; - dst[0] = v >> 8; - dst[1] = v; - dst += 2; + uint32_t tmp = ff_reverse[(*samples >> 8) & 0xff] + + (ff_reverse[*samples & 0xff] << 8); + tmp <<= 4; // sync flags would go here + bytestream_put_be24(&dst, tmp); + samples++; } break; case CODEC_ID_PCM_U16LE: - for(;n>0;n--) { - v = *samples++; - v += 0x8000; - dst[0] = v & 0xff; - dst[1] = v >> 8; - dst += 2; - } + ENCODE(uint16_t, le16, samples, dst, n, 0, 0x8000) break; case CODEC_ID_PCM_U16BE: - for(;n>0;n--) { - v = *samples++; - v += 0x8000; - dst[0] = v >> 8; - dst[1] = v; - dst += 2; - } + ENCODE(uint16_t, be16, samples, dst, n, 0, 0x8000) break; case CODEC_ID_PCM_S8: + srcu8= data; for(;n>0;n--) { - v = *samples++; - dst[0] = v >> 8; - dst++; + v = *srcu8++; + *dst++ = v - 128; } break; +#if WORDS_BIGENDIAN + case CODEC_ID_PCM_F64LE: + ENCODE(int64_t, le64, samples, dst, n, 0, 0) + break; + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_F32LE: + ENCODE(int32_t, le32, samples, dst, n, 0, 0) + break; + case CODEC_ID_PCM_S16LE: + ENCODE(int16_t, le16, samples, dst, n, 0, 0) + break; + case CODEC_ID_PCM_F64BE: + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_S16BE: +#else + case CODEC_ID_PCM_F64BE: + ENCODE(int64_t, be64, samples, dst, n, 0, 0) + break; + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_S32BE: + ENCODE(int32_t, be32, samples, dst, n, 0, 0) + break; + case CODEC_ID_PCM_S16BE: + ENCODE(int16_t, be16, samples, dst, n, 0, 0) + break; + case CODEC_ID_PCM_F64LE: + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S16LE: +#endif /* WORDS_BIGENDIAN */ case CODEC_ID_PCM_U8: + memcpy(dst, samples, n*sample_size); + dst += n*sample_size; + break; + case CODEC_ID_PCM_ZORK: for(;n>0;n--) { - v = *samples++; - dst[0] = (v >> 8) + 128; - dst++; + v= *samples++ >> 8; + if(v<0) v = -v; + else v+= 128; + *dst++ = v; } break; case CODEC_ID_PCM_ALAW: for(;n>0;n--) { v = *samples++; - dst[0] = linear_to_alaw[(v + 32768) >> 2]; - dst++; + *dst++ = linear_to_alaw[(v + 32768) >> 2]; } break; case CODEC_ID_PCM_MULAW: for(;n>0;n--) { v = *samples++; - dst[0] = linear_to_ulaw[(v + 32768) >> 2]; - dst++; + *dst++ = linear_to_ulaw[(v + 32768) >> 2]; } break; default: @@ -250,7 +280,7 @@ typedef struct PCMDecode { short table[256]; } PCMDecode; -static int pcm_decode_init(AVCodecContext * avctx) +static av_cold int pcm_decode_init(AVCodecContext * avctx) { PCMDecode *s = avctx->priv_data; int i; @@ -267,109 +297,276 @@ static int pcm_decode_init(AVCodecContext * avctx) default: break; } + + avctx->sample_fmt = avctx->codec->sample_fmts[0]; return 0; } +/** + * Read PCM samples macro + * @param type Datatype of native machine format + * @param endian bytestream_get_xxx() endian suffix + * @param src Source pointer (variable name) + * @param dst Destination pointer (variable name) + * @param n Total number of samples (variable name) + * @param shift Bitshift (bits) + * @param offset Sample value offset + */ +#define DECODE(type, endian, src, dst, n, shift, offset) \ + dst_##type = (type*)dst; \ + for(;n>0;n--) { \ + register type v = bytestream_get_##endian(&src); \ + *dst_##type++ = (v - offset) << shift; \ + } \ + dst = (short*)dst_##type; + static int pcm_decode_frame(AVCodecContext *avctx, - void *data, int *data_size, - uint8_t *buf, int buf_size) + void *data, int *data_size, + const uint8_t *buf, int buf_size) { PCMDecode *s = avctx->priv_data; - int n; + int sample_size, c, n; short *samples; - uint8_t *src; + const uint8_t *src, *src8, *src2[MAX_CHANNELS]; + uint8_t *dstu8; + int16_t *dst_int16_t; + int32_t *dst_int32_t; + int64_t *dst_int64_t; + uint16_t *dst_uint16_t; + uint32_t *dst_uint32_t; samples = data; src = buf; + if (avctx->sample_fmt!=avctx->codec->sample_fmts[0]) { + av_log(avctx, AV_LOG_ERROR, "invalid sample_fmt\n"); + return -1; + } + + if(avctx->channels <= 0 || avctx->channels > MAX_CHANNELS){ + av_log(avctx, AV_LOG_ERROR, "PCM channels out of bounds\n"); + return -1; + } + + sample_size = av_get_bits_per_sample(avctx->codec_id)/8; + + /* av_get_bits_per_sample returns 0 for CODEC_ID_PCM_DVD */ + if (CODEC_ID_PCM_DVD == avctx->codec_id) + /* 2 samples are interleaved per block in PCM_DVD */ + sample_size = avctx->bits_per_sample * 2 / 8; + + n = avctx->channels * sample_size; + + if(n && buf_size % n){ + av_log(avctx, AV_LOG_ERROR, "invalid PCM packet\n"); + return -1; + } + + buf_size= FFMIN(buf_size, *data_size/2); + *data_size=0; + + n = buf_size/sample_size; + switch(avctx->codec->id) { - case CODEC_ID_PCM_S16LE: - n = buf_size >> 1; + case CODEC_ID_PCM_U32LE: + DECODE(uint32_t, le32, src, samples, n, 0, 0x80000000) + break; + case CODEC_ID_PCM_U32BE: + DECODE(uint32_t, be32, src, samples, n, 0, 0x80000000) + break; + case CODEC_ID_PCM_S24LE: + DECODE(int32_t, le24, src, samples, n, 8, 0) + break; + case CODEC_ID_PCM_S24BE: + DECODE(int32_t, be24, src, samples, n, 8, 0) + break; + case CODEC_ID_PCM_U24LE: + DECODE(uint32_t, le24, src, samples, n, 8, 0x800000) + break; + case CODEC_ID_PCM_U24BE: + DECODE(uint32_t, be24, src, samples, n, 8, 0x800000) + break; + case CODEC_ID_PCM_S24DAUD: for(;n>0;n--) { - *samples++ = src[0] | (src[1] << 8); - src += 2; + uint32_t v = bytestream_get_be24(&src); + v >>= 4; // sync flags are here + *samples++ = ff_reverse[(v >> 8) & 0xff] + + (ff_reverse[v & 0xff] << 8); } break; - case CODEC_ID_PCM_S16BE: - n = buf_size >> 1; - for(;n>0;n--) { - *samples++ = (src[0] << 8) | src[1]; - src += 2; - } + case CODEC_ID_PCM_S16LE_PLANAR: + n /= avctx->channels; + for(c=0;cchannels;c++) + src2[c] = &src[c*n*2]; + for(;n>0;n--) + for(c=0;cchannels;c++) + *samples++ = bytestream_get_le16(&src2[c]); + src = src2[avctx->channels-1]; break; case CODEC_ID_PCM_U16LE: - n = buf_size >> 1; - for(;n>0;n--) { - *samples++ = (src[0] | (src[1] << 8)) - 0x8000; - src += 2; - } + DECODE(uint16_t, le16, src, samples, n, 0, 0x8000) break; case CODEC_ID_PCM_U16BE: - n = buf_size >> 1; - for(;n>0;n--) { - *samples++ = ((src[0] << 8) | src[1]) - 0x8000; - src += 2; - } + DECODE(uint16_t, be16, src, samples, n, 0, 0x8000) break; case CODEC_ID_PCM_S8: - n = buf_size; + dstu8= (uint8_t*)samples; for(;n>0;n--) { - *samples++ = src[0] << 8; - src++; + *dstu8++ = *src++ + 128; } + samples= (short*)dstu8; break; +#if WORDS_BIGENDIAN + case CODEC_ID_PCM_F64LE: + DECODE(int64_t, le64, src, samples, n, 0, 0) + break; + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_F32LE: + DECODE(int32_t, le32, src, samples, n, 0, 0) + break; + case CODEC_ID_PCM_S16LE: + DECODE(int16_t, le16, src, samples, n, 0, 0) + break; + case CODEC_ID_PCM_F64BE: + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_S16BE: +#else + case CODEC_ID_PCM_F64BE: + DECODE(int64_t, be64, src, samples, n, 0, 0) + break; + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_S32BE: + DECODE(int32_t, be32, src, samples, n, 0, 0) + break; + case CODEC_ID_PCM_S16BE: + DECODE(int16_t, be16, src, samples, n, 0, 0) + break; + case CODEC_ID_PCM_F64LE: + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S16LE: +#endif /* WORDS_BIGENDIAN */ case CODEC_ID_PCM_U8: - n = buf_size; + memcpy(samples, src, n*sample_size); + src += n*sample_size; + samples = (short*)((uint8_t*)data + n*sample_size); + break; + case CODEC_ID_PCM_ZORK: for(;n>0;n--) { - *samples++ = ((int)src[0] - 128) << 8; - src++; + int x= *src++; + if(x&128) x-= 128; + else x = -x; + *samples++ = x << 8; } break; case CODEC_ID_PCM_ALAW: case CODEC_ID_PCM_MULAW: - n = buf_size; for(;n>0;n--) { - *samples++ = s->table[src[0]]; - src++; + *samples++ = s->table[*src++]; } break; + case CODEC_ID_PCM_DVD: + dst_int32_t = data; + n /= avctx->channels; + switch (avctx->bits_per_sample) { + case 20: + while (n--) { + c = avctx->channels; + src8 = src + 4*c; + while (c--) { + *dst_int32_t++ = (bytestream_get_be16(&src) << 16) + ((*src8 &0xf0) << 8); + *dst_int32_t++ = (bytestream_get_be16(&src) << 16) + ((*src8++ &0x0f) << 12); + } + src = src8; + } + break; + case 24: + while (n--) { + c = avctx->channels; + src8 = src + 4*c; + while (c--) { + *dst_int32_t++ = (bytestream_get_be16(&src) << 16) + ((*src8++) << 8); + *dst_int32_t++ = (bytestream_get_be16(&src) << 16) + ((*src8++) << 8); + } + src = src8; + } + break; + default: + av_log(avctx, AV_LOG_ERROR, "PCM DVD unsupported sample depth\n"); + return -1; + break; + } + samples = (short *) dst_int32_t; + break; default: - *data_size = 0; return -1; } *data_size = (uint8_t *)samples - (uint8_t *)data; return src - buf; } -#define PCM_CODEC(id, name) \ +#ifdef CONFIG_ENCODERS +#define PCM_ENCODER(id,sample_fmt_,name,long_name_) \ AVCodec name ## _encoder = { \ #name, \ CODEC_TYPE_AUDIO, \ id, \ 0, \ - pcm_encode_init, \ - pcm_encode_frame, \ - pcm_encode_close, \ + pcm_encode_init, \ + pcm_encode_frame, \ + pcm_encode_close, \ NULL, \ -}; \ + .sample_fmts = (enum SampleFormat[]){sample_fmt_,SAMPLE_FMT_NONE}, \ + .long_name = NULL_IF_CONFIG_SMALL(long_name_), \ +}; +#else +#define PCM_ENCODER(id,sample_fmt_,name,long_name_) +#endif + +#ifdef CONFIG_DECODERS +#define PCM_DECODER(id,sample_fmt_,name,long_name_) \ AVCodec name ## _decoder = { \ #name, \ CODEC_TYPE_AUDIO, \ id, \ sizeof(PCMDecode), \ - pcm_decode_init, \ + pcm_decode_init, \ NULL, \ NULL, \ pcm_decode_frame, \ -} + .sample_fmts = (enum SampleFormat[]){sample_fmt_,SAMPLE_FMT_NONE}, \ + .long_name = NULL_IF_CONFIG_SMALL(long_name_), \ +}; +#else +#define PCM_DECODER(id,sample_fmt_,name,long_name_) +#endif -PCM_CODEC(CODEC_ID_PCM_S16LE, pcm_s16le); -PCM_CODEC(CODEC_ID_PCM_S16BE, pcm_s16be); -PCM_CODEC(CODEC_ID_PCM_U16LE, pcm_u16le); -PCM_CODEC(CODEC_ID_PCM_U16BE, pcm_u16be); -PCM_CODEC(CODEC_ID_PCM_S8, pcm_s8); -PCM_CODEC(CODEC_ID_PCM_U8, pcm_u8); -PCM_CODEC(CODEC_ID_PCM_ALAW, pcm_alaw); -PCM_CODEC(CODEC_ID_PCM_MULAW, pcm_mulaw); +#define PCM_CODEC(id, sample_fmt_, name, long_name_) \ + PCM_ENCODER(id,sample_fmt_,name,long_name_) PCM_DECODER(id,sample_fmt_,name,long_name_) -#undef PCM_CODEC +/* Note: Do not forget to add new entries to the Makefile as well. */ +PCM_CODEC (CODEC_ID_PCM_ALAW, SAMPLE_FMT_S16, pcm_alaw, "A-law PCM"); +PCM_CODEC (CODEC_ID_PCM_DVD, SAMPLE_FMT_S32, pcm_dvd, "signed 20|24-bit big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_F32BE, SAMPLE_FMT_FLT, pcm_f32be, "32-bit floating point big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_F32LE, SAMPLE_FMT_FLT, pcm_f32le, "32-bit floating point little-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_F64BE, SAMPLE_FMT_DBL, pcm_f64be, "64-bit floating point big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_F64LE, SAMPLE_FMT_DBL, pcm_f64le, "64-bit floating point little-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_MULAW, SAMPLE_FMT_S16, pcm_mulaw, "mu-law PCM"); +PCM_CODEC (CODEC_ID_PCM_S8, SAMPLE_FMT_U8, pcm_s8, "signed 8-bit PCM"); +PCM_CODEC (CODEC_ID_PCM_S16BE, SAMPLE_FMT_S16, pcm_s16be, "signed 16-bit big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_S16LE, SAMPLE_FMT_S16, pcm_s16le, "signed 16-bit little-endian PCM"); +PCM_DECODER(CODEC_ID_PCM_S16LE_PLANAR, SAMPLE_FMT_S16, pcm_s16le_planar, "16-bit little-endian planar PCM"); +PCM_CODEC (CODEC_ID_PCM_S24BE, SAMPLE_FMT_S32, pcm_s24be, "signed 24-bit big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_S24DAUD, SAMPLE_FMT_S16, pcm_s24daud, "D-Cinema audio signed 24-bit PCM"); +PCM_CODEC (CODEC_ID_PCM_S24LE, SAMPLE_FMT_S32, pcm_s24le, "signed 24-bit little-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_S32BE, SAMPLE_FMT_S32, pcm_s32be, "signed 32-bit big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_S32LE, SAMPLE_FMT_S32, pcm_s32le, "signed 32-bit little-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_U8, SAMPLE_FMT_U8, pcm_u8, "unsigned 8-bit PCM"); +PCM_CODEC (CODEC_ID_PCM_U16BE, SAMPLE_FMT_S16, pcm_u16be, "unsigned 16-bit big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_U16LE, SAMPLE_FMT_S16, pcm_u16le, "unsigned 16-bit little-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_U24BE, SAMPLE_FMT_S32, pcm_u24be, "unsigned 24-bit big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_U24LE, SAMPLE_FMT_S32, pcm_u24le, "unsigned 24-bit little-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_U32BE, SAMPLE_FMT_S32, pcm_u32be, "unsigned 32-bit big-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_U32LE, SAMPLE_FMT_S32, pcm_u32le, "unsigned 32-bit little-endian PCM"); +PCM_CODEC (CODEC_ID_PCM_ZORK, SAMPLE_FMT_S16, pcm_zork, "Zork PCM"); diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pcx.c b/src/add-ons/media/plugins/avcodec/libavcodec/pcx.c new file mode 100644 index 0000000000..bf80e437fe --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pcx.c @@ -0,0 +1,248 @@ +/* + * PC Paintbrush PCX (.pcx) image decoder + * Copyright (c) 2007, 2008 Ivo van Poorten + * + * This decoder does not support CGA palettes. I am unable to find samples + * and Netpbm cannot generate them. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "bytestream.h" +#include "bitstream.h" + +typedef struct PCXContext { + AVFrame picture; +} PCXContext; + +static av_cold int pcx_init(AVCodecContext *avctx) { + PCXContext *s = avctx->priv_data; + + avcodec_get_frame_defaults(&s->picture); + avctx->coded_frame= &s->picture; + + return 0; +} + +/** + * @return advanced src pointer + */ +static const uint8_t *pcx_rle_decode(const uint8_t *src, uint8_t *dst, + unsigned int bytes_per_scanline) { + unsigned int i = 0; + unsigned char run, value; + + while (i= 0xc0) { + run = value & 0x3f; + value = *src++; + } + while (ipriv_data; + AVFrame *picture = data; + AVFrame * const p = &s->picture; + int xmin, ymin, xmax, ymax; + unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x, + bytes_per_scanline; + uint8_t *ptr; + uint8_t const *bufstart = buf; + + if (buf[0] != 0x0a || buf[1] > 5 || buf[1] == 1 || buf[2] != 1) { + av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n"); + return -1; + } + + xmin = AV_RL16(buf+ 4); + ymin = AV_RL16(buf+ 6); + xmax = AV_RL16(buf+ 8); + ymax = AV_RL16(buf+10); + + if (xmax < xmin || ymax < ymin) { + av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n"); + return -1; + } + + w = xmax - xmin + 1; + h = ymax - ymin + 1; + + bits_per_pixel = buf[3]; + bytes_per_line = AV_RL16(buf+66); + nplanes = buf[65]; + bytes_per_scanline = nplanes * bytes_per_line; + + if (bytes_per_scanline < w * bits_per_pixel * nplanes / 8) { + av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n"); + return -1; + } + + switch ((nplanes<<8) + bits_per_pixel) { + case 0x0308: + avctx->pix_fmt = PIX_FMT_RGB24; + break; + case 0x0108: + case 0x0104: + case 0x0102: + case 0x0101: + case 0x0401: + case 0x0301: + case 0x0201: + avctx->pix_fmt = PIX_FMT_PAL8; + break; + default: + av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n"); + return -1; + } + + buf += 128; + + if (p->data[0]) + avctx->release_buffer(avctx, p); + + if (avcodec_check_dimensions(avctx, w, h)) + return -1; + if (w != avctx->width || h != avctx->height) + avcodec_set_dimensions(avctx, w, h); + if (avctx->get_buffer(avctx, p) < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + + p->pict_type = FF_I_TYPE; + + ptr = p->data[0]; + stride = p->linesize[0]; + + if (nplanes == 3 && bits_per_pixel == 8) { + uint8_t scanline[bytes_per_scanline]; + + for (y=0; y> (x&7), v = 0; + for (i=nplanes - 1; i>=0; i--) { + v <<= 1; + v += !!(scanline[i*bytes_per_line + (x>>3)] & m); + } + ptr[x] = v; + } + ptr += stride; + } + } + + if (nplanes == 1 && bits_per_pixel == 8) { + pcx_palette(&buf, (uint32_t *) p->data[1], 256); + } else if (bits_per_pixel < 8) { + const uint8_t *palette = bufstart+16; + pcx_palette(&palette, (uint32_t *) p->data[1], 16); + } + + *picture = s->picture; + *data_size = sizeof(AVFrame); + + return buf - bufstart; +} + +static av_cold int pcx_end(AVCodecContext *avctx) { + PCXContext *s = avctx->priv_data; + + if(s->picture.data[0]) + avctx->release_buffer(avctx, &s->picture); + + return 0; +} + +AVCodec pcx_decoder = { + "pcx", + CODEC_TYPE_VIDEO, + CODEC_ID_PCX, + sizeof(PCXContext), + pcx_init, + NULL, + pcx_end, + pcx_decode_frame, + 0, + NULL, + .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/png.c b/src/add-ons/media/plugins/avcodec/libavcodec/png.c new file mode 100644 index 0000000000..c95ba3e10d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/png.c @@ -0,0 +1,83 @@ +/* + * PNG image format + * Copyright (c) 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avcodec.h" +#include "bytestream.h" +#include "png.h" + +const uint8_t ff_pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; +const uint8_t ff_mngsig[8] = {138, 77, 78, 71, 13, 10, 26, 10}; + +/* Mask to determine which y pixels are valid in a pass */ +const uint8_t ff_png_pass_ymask[NB_PASSES] = { + 0x80, 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, +}; + +/* minimum x value */ +const uint8_t ff_png_pass_xmin[NB_PASSES] = { + 0, 4, 0, 2, 0, 1, 0 +}; + +/* x shift to get row width */ +const uint8_t ff_png_pass_xshift[NB_PASSES] = { + 3, 3, 2, 2, 1, 1, 0 +}; + +/* Mask to determine which pixels are valid in a pass */ +const uint8_t ff_png_pass_mask[NB_PASSES] = { + 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff +}; + +void *ff_png_zalloc(void *opaque, unsigned int items, unsigned int size) +{ + if(items >= UINT_MAX / size) + return NULL; + return av_malloc(items * size); +} + +void ff_png_zfree(void *opaque, void *ptr) +{ + av_free(ptr); +} + +int ff_png_get_nb_channels(int color_type) +{ + int channels; + channels = 1; + if ((color_type & (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)) == + PNG_COLOR_MASK_COLOR) + channels = 3; + if (color_type & PNG_COLOR_MASK_ALPHA) + channels++; + return channels; +} + +/* compute the row size of an interleaved pass */ +int ff_png_pass_row_size(int pass, int bits_per_pixel, int width) +{ + int shift, xmin, pass_width; + + xmin = ff_png_pass_xmin[pass]; + if (width <= xmin) + return 0; + shift = ff_png_pass_xshift[pass]; + pass_width = (width - xmin + (1 << shift) - 1) >> shift; + return (pass_width * bits_per_pixel + 7) >> 3; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/png.h b/src/add-ons/media/plugins/avcodec/libavcodec/png.h new file mode 100644 index 0000000000..6e16f62e0f --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/png.h @@ -0,0 +1,77 @@ +/* + * PNG image format + * Copyright (c) 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FFMPEG_PNG_H +#define FFMPEG_PNG_H + +#include + +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) + +#define PNG_FILTER_TYPE_LOCO 64 +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_MIXED 5 + +#define PNG_IHDR 0x0001 +#define PNG_IDAT 0x0002 +#define PNG_ALLIMAGE 0x0004 +#define PNG_PLTE 0x0008 + +#define NB_PASSES 7 + +extern const uint8_t ff_pngsig[8]; +extern const uint8_t ff_mngsig[8]; + +/* Mask to determine which y pixels are valid in a pass */ +extern const uint8_t ff_png_pass_ymask[NB_PASSES]; + +/* minimum x value */ +extern const uint8_t ff_png_pass_xmin[NB_PASSES]; + +/* x shift to get row width */ +extern const uint8_t ff_png_pass_xshift[NB_PASSES]; + +/* Mask to determine which pixels are valid in a pass */ +extern const uint8_t ff_png_pass_mask[NB_PASSES]; + +extern void *ff_png_zalloc(void *opaque, unsigned int items, + unsigned int size); + +extern void ff_png_zfree(void *opaque, void *ptr); + +extern int ff_png_get_nb_channels(int color_type); + +/* compute the row size of an interleaved pass */ +extern int ff_png_pass_row_size(int pass, int bits_per_pixel, int width); + +#endif /* FFMPEG_PNG_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pngdec.c b/src/add-ons/media/plugins/avcodec/libavcodec/pngdec.c new file mode 100644 index 0000000000..77ac0d155d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pngdec.c @@ -0,0 +1,622 @@ +/* + * PNG image format + * Copyright (c) 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avcodec.h" +#include "bytestream.h" +#include "png.h" +#include "dsputil.h" + +/* TODO: + * - add 2, 4 and 16 bit depth support + */ + +#include + +//#define DEBUG + +typedef struct PNGDecContext { + DSPContext dsp; + + const uint8_t *bytestream; + const uint8_t *bytestream_start; + const uint8_t *bytestream_end; + AVFrame picture; + + int state; + int width, height; + int bit_depth; + int color_type; + int compression_type; + int interlace_type; + int filter_type; + int channels; + int bits_per_pixel; + int bpp; + + uint8_t *image_buf; + int image_linesize; + uint32_t palette[256]; + uint8_t *crow_buf; + uint8_t *last_row; + uint8_t *tmp_row; + int pass; + int crow_size; /* compressed row size (include filter type) */ + int row_size; /* decompressed row size */ + int pass_row_size; /* decompress row size of the current pass */ + int y; + z_stream zstream; +} PNGDecContext; + +/* Mask to determine which y pixels can be written in a pass */ +static const uint8_t png_pass_dsp_ymask[NB_PASSES] = { + 0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55, +}; + +/* Mask to determine which pixels to overwrite while displaying */ +static const uint8_t png_pass_dsp_mask[NB_PASSES] = { + 0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff +}; + +/* NOTE: we try to construct a good looking image at each pass. width + is the original image width. We also do pixel format conversion at + this stage */ +static void png_put_interlaced_row(uint8_t *dst, int width, + int bits_per_pixel, int pass, + int color_type, const uint8_t *src) +{ + int x, mask, dsp_mask, j, src_x, b, bpp; + uint8_t *d; + const uint8_t *s; + + mask = ff_png_pass_mask[pass]; + dsp_mask = png_pass_dsp_mask[pass]; + switch(bits_per_pixel) { + case 1: + /* we must initialize the line to zero before writing to it */ + if (pass == 0) + memset(dst, 0, (width + 7) >> 3); + src_x = 0; + for(x = 0; x < width; x++) { + j = (x & 7); + if ((dsp_mask << j) & 0x80) { + b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1; + dst[x >> 3] |= b << (7 - j); + } + if ((mask << j) & 0x80) + src_x++; + } + break; + default: + bpp = bits_per_pixel >> 3; + d = dst; + s = src; + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + for(x = 0; x < width; x++) { + j = x & 7; + if ((dsp_mask << j) & 0x80) { + *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2]; + } + d += bpp; + if ((mask << j) & 0x80) + s += bpp; + } + } else { + for(x = 0; x < width; x++) { + j = x & 7; + if ((dsp_mask << j) & 0x80) { + memcpy(d, s, bpp); + } + d += bpp; + if ((mask << j) & 0x80) + s += bpp; + } + } + break; + } +} + +void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp) +{ + int i; + for(i = 0; i < w; i++) { + int a, b, c, p, pa, pb, pc; + + a = dst[i - bpp]; + b = top[i]; + c = top[i - bpp]; + + p = b - c; + pc = a - c; + + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); + + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + dst[i] = p + src[i]; + } +} + +#define UNROLL1(bpp, op) {\ + r = dst[0];\ + if(bpp >= 2) g = dst[1];\ + if(bpp >= 3) b = dst[2];\ + if(bpp >= 4) a = dst[3];\ + for(; i < size; i+=bpp) {\ + dst[i+0] = r = op(r, src[i+0], last[i+0]);\ + if(bpp == 1) continue;\ + dst[i+1] = g = op(g, src[i+1], last[i+1]);\ + if(bpp == 2) continue;\ + dst[i+2] = b = op(b, src[i+2], last[i+2]);\ + if(bpp == 3) continue;\ + dst[i+3] = a = op(a, src[i+3], last[i+3]);\ + }\ +} + +#define UNROLL_FILTER(op)\ + if(bpp == 1) UNROLL1(1, op)\ + else if(bpp == 2) UNROLL1(2, op)\ + else if(bpp == 3) UNROLL1(3, op)\ + else if(bpp == 4) UNROLL1(4, op)\ + +/* NOTE: 'dst' can be equal to 'last' */ +static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type, + uint8_t *src, uint8_t *last, int size, int bpp) +{ + int i, p, r, g, b, a; + + switch(filter_type) { + case PNG_FILTER_VALUE_NONE: + memcpy(dst, src, size); + break; + case PNG_FILTER_VALUE_SUB: + for(i = 0; i < bpp; i++) { + dst[i] = src[i]; + } + if(bpp == 4) { + p = *(int*)dst; + for(; i < size; i+=bpp) { + int s = *(int*)(src+i); + p = ((s&0x7f7f7f7f) + (p&0x7f7f7f7f)) ^ ((s^p)&0x80808080); + *(int*)(dst+i) = p; + } + } else { +#define OP_SUB(x,s,l) x+s + UNROLL_FILTER(OP_SUB); + } + break; + case PNG_FILTER_VALUE_UP: + dsp->add_bytes_l2(dst, src, last, size); + break; + case PNG_FILTER_VALUE_AVG: + for(i = 0; i < bpp; i++) { + p = (last[i] >> 1); + dst[i] = p + src[i]; + } +#define OP_AVG(x,s,l) (((x + l) >> 1) + s) & 0xff + UNROLL_FILTER(OP_AVG); + break; + case PNG_FILTER_VALUE_PAETH: + for(i = 0; i < bpp; i++) { + p = last[i]; + dst[i] = p + src[i]; + } + if(bpp > 1 && size > 4) { + // would write off the end of the array if we let it process the last pixel with bpp=3 + int w = bpp==4 ? size : size-3; + dsp->add_png_paeth_prediction(dst+i, src+i, last+i, w-i, bpp); + i = w; + } + ff_add_png_paeth_prediction(dst+i, src+i, last+i, size-i, bpp); + break; + } +} + +static av_always_inline void convert_to_rgb32_loco(uint8_t *dst, const uint8_t *src, int width, int loco) +{ + int j; + unsigned int r, g, b, a; + + for(j = 0;j < width; j++) { + r = src[0]; + g = src[1]; + b = src[2]; + a = src[3]; + if(loco) { + r = (r+g)&0xff; + b = (b+g)&0xff; + } + *(uint32_t *)dst = (a << 24) | (r << 16) | (g << 8) | b; + dst += 4; + src += 4; + } +} + +static void convert_to_rgb32(uint8_t *dst, const uint8_t *src, int width, int loco) +{ + if(loco) + convert_to_rgb32_loco(dst, src, width, 1); + else + convert_to_rgb32_loco(dst, src, width, 0); +} + +static void deloco_rgb24(uint8_t *dst, int size) +{ + int i; + for(i=0; iinterlace_type) { + ptr = s->image_buf + s->image_linesize * s->y; + /* need to swap bytes correctly for RGB_ALPHA */ + if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1, + s->last_row, s->row_size, s->bpp); + convert_to_rgb32(ptr, s->tmp_row, s->width, s->filter_type == PNG_FILTER_TYPE_LOCO); + FFSWAP(uint8_t*, s->last_row, s->tmp_row); + } else { + /* in normal case, we avoid one copy */ + if (s->y == 0) + last_row = s->last_row; + else + last_row = ptr - s->image_linesize; + + png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1, + last_row, s->row_size, s->bpp); + } + /* loco lags by 1 row so that it doesn't interfere with top prediction */ + if (s->filter_type == PNG_FILTER_TYPE_LOCO && + s->color_type == PNG_COLOR_TYPE_RGB && s->y > 0) + deloco_rgb24(ptr - s->image_linesize, s->row_size); + s->y++; + if (s->y == s->height) { + s->state |= PNG_ALLIMAGE; + if (s->filter_type == PNG_FILTER_TYPE_LOCO && + s->color_type == PNG_COLOR_TYPE_RGB) + deloco_rgb24(ptr, s->row_size); + } + } else { + got_line = 0; + for(;;) { + ptr = s->image_buf + s->image_linesize * s->y; + if ((ff_png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) { + /* if we already read one row, it is time to stop to + wait for the next one */ + if (got_line) + break; + png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1, + s->last_row, s->pass_row_size, s->bpp); + FFSWAP(uint8_t*, s->last_row, s->tmp_row); + got_line = 1; + } + if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) { + /* NOTE: RGB32 is handled directly in png_put_interlaced_row */ + png_put_interlaced_row(ptr, s->width, s->bits_per_pixel, s->pass, + s->color_type, s->last_row); + } + s->y++; + if (s->y == s->height) { + for(;;) { + if (s->pass == NB_PASSES - 1) { + s->state |= PNG_ALLIMAGE; + goto the_end; + } else { + s->pass++; + s->y = 0; + s->pass_row_size = ff_png_pass_row_size(s->pass, + s->bits_per_pixel, + s->width); + s->crow_size = s->pass_row_size + 1; + if (s->pass_row_size != 0) + break; + /* skip pass if empty row */ + } + } + } + } + the_end: ; + } +} + +static int png_decode_idat(PNGDecContext *s, int length) +{ + int ret; + s->zstream.avail_in = length; + s->zstream.next_in = s->bytestream; + s->bytestream += length; + + if(s->bytestream > s->bytestream_end) + return -1; + + /* decode one line if possible */ + while (s->zstream.avail_in > 0) { + ret = inflate(&s->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) { + return -1; + } + if (s->zstream.avail_out == 0) { + if (!(s->state & PNG_ALLIMAGE)) { + png_handle_row(s); + } + s->zstream.avail_out = s->crow_size; + s->zstream.next_out = s->crow_buf; + } + } + return 0; +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + PNGDecContext * const s = avctx->priv_data; + AVFrame *picture = data; + AVFrame * const p= &s->picture; + uint32_t tag, length; + int ret, crc; + + s->bytestream_start= + s->bytestream= buf; + s->bytestream_end= buf + buf_size; + + /* check signature */ + if (memcmp(s->bytestream, ff_pngsig, 8) != 0 && + memcmp(s->bytestream, ff_mngsig, 8) != 0) + return -1; + s->bytestream+= 8; + s->y= + s->state=0; +// memset(s, 0, sizeof(PNGDecContext)); + /* init the zlib */ + s->zstream.zalloc = ff_png_zalloc; + s->zstream.zfree = ff_png_zfree; + s->zstream.opaque = NULL; + ret = inflateInit(&s->zstream); + if (ret != Z_OK) + return -1; + for(;;) { + int tag32; + if (s->bytestream >= s->bytestream_end) + goto fail; + length = bytestream_get_be32(&s->bytestream); + if (length > 0x7fffffff) + goto fail; + tag32 = bytestream_get_be32(&s->bytestream); + tag = bswap_32(tag32); +#ifdef DEBUG + av_log(avctx, AV_LOG_DEBUG, "png: tag=%c%c%c%c length=%u\n", + (tag & 0xff), + ((tag >> 8) & 0xff), + ((tag >> 16) & 0xff), + ((tag >> 24) & 0xff), length); +#endif + switch(tag) { + case MKTAG('I', 'H', 'D', 'R'): + if (length != 13) + goto fail; + s->width = bytestream_get_be32(&s->bytestream); + s->height = bytestream_get_be32(&s->bytestream); + if(avcodec_check_dimensions(avctx, s->width, s->height)){ + s->width= s->height= 0; + goto fail; + } + s->bit_depth = *s->bytestream++; + s->color_type = *s->bytestream++; + s->compression_type = *s->bytestream++; + s->filter_type = *s->bytestream++; + s->interlace_type = *s->bytestream++; + crc = bytestream_get_be32(&s->bytestream); + s->state |= PNG_IHDR; +#ifdef DEBUG + av_log(avctx, AV_LOG_DEBUG, "width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n", + s->width, s->height, s->bit_depth, s->color_type, + s->compression_type, s->filter_type, s->interlace_type); +#endif + break; + case MKTAG('I', 'D', 'A', 'T'): + if (!(s->state & PNG_IHDR)) + goto fail; + if (!(s->state & PNG_IDAT)) { + /* init image info */ + avctx->width = s->width; + avctx->height = s->height; + + s->channels = ff_png_get_nb_channels(s->color_type); + s->bits_per_pixel = s->bit_depth * s->channels; + s->bpp = (s->bits_per_pixel + 7) >> 3; + s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3; + + if (s->bit_depth == 8 && + s->color_type == PNG_COLOR_TYPE_RGB) { + avctx->pix_fmt = PIX_FMT_RGB24; + } else if (s->bit_depth == 8 && + s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + avctx->pix_fmt = PIX_FMT_RGB32; + } else if (s->bit_depth == 8 && + s->color_type == PNG_COLOR_TYPE_GRAY) { + avctx->pix_fmt = PIX_FMT_GRAY8; + } else if (s->bit_depth == 16 && + s->color_type == PNG_COLOR_TYPE_GRAY) { + avctx->pix_fmt = PIX_FMT_GRAY16BE; + } else if (s->bit_depth == 1 && + s->color_type == PNG_COLOR_TYPE_GRAY) { + avctx->pix_fmt = PIX_FMT_MONOBLACK; + } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) { + avctx->pix_fmt = PIX_FMT_PAL8; + } else { + goto fail; + } + if(p->data[0]) + avctx->release_buffer(avctx, p); + + p->reference= 0; + if(avctx->get_buffer(avctx, p) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + goto fail; + } + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + p->interlaced_frame = !!s->interlace_type; + + /* compute the compressed row size */ + if (!s->interlace_type) { + s->crow_size = s->row_size + 1; + } else { + s->pass = 0; + s->pass_row_size = ff_png_pass_row_size(s->pass, + s->bits_per_pixel, + s->width); + s->crow_size = s->pass_row_size + 1; + } +#ifdef DEBUG + av_log(avctx, AV_LOG_DEBUG, "row_size=%d crow_size =%d\n", + s->row_size, s->crow_size); +#endif + s->image_buf = p->data[0]; + s->image_linesize = p->linesize[0]; + /* copy the palette if needed */ + if (s->color_type == PNG_COLOR_TYPE_PALETTE) + memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t)); + /* empty row is used if differencing to the first row */ + s->last_row = av_mallocz(s->row_size); + if (!s->last_row) + goto fail; + if (s->interlace_type || + s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + s->tmp_row = av_malloc(s->row_size); + if (!s->tmp_row) + goto fail; + } + /* compressed row */ + s->crow_buf = av_malloc(s->row_size + 1); + if (!s->crow_buf) + goto fail; + s->zstream.avail_out = s->crow_size; + s->zstream.next_out = s->crow_buf; + } + s->state |= PNG_IDAT; + if (png_decode_idat(s, length) < 0) + goto fail; + /* skip crc */ + crc = bytestream_get_be32(&s->bytestream); + break; + case MKTAG('P', 'L', 'T', 'E'): + { + int n, i, r, g, b; + + if ((length % 3) != 0 || length > 256 * 3) + goto skip_tag; + /* read the palette */ + n = length / 3; + for(i=0;ibytestream++; + g = *s->bytestream++; + b = *s->bytestream++; + s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b; + } + for(;i<256;i++) { + s->palette[i] = (0xff << 24); + } + s->state |= PNG_PLTE; + crc = bytestream_get_be32(&s->bytestream); + } + break; + case MKTAG('t', 'R', 'N', 'S'): + { + int v, i; + + /* read the transparency. XXX: Only palette mode supported */ + if (s->color_type != PNG_COLOR_TYPE_PALETTE || + length > 256 || + !(s->state & PNG_PLTE)) + goto skip_tag; + for(i=0;ibytestream++; + s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24); + } + crc = bytestream_get_be32(&s->bytestream); + } + break; + case MKTAG('I', 'E', 'N', 'D'): + if (!(s->state & PNG_ALLIMAGE)) + goto fail; + crc = bytestream_get_be32(&s->bytestream); + goto exit_loop; + default: + /* skip tag */ + skip_tag: + s->bytestream += length + 4; + break; + } + } + exit_loop: + *picture= s->picture; + *data_size = sizeof(AVFrame); + + ret = s->bytestream - s->bytestream_start; + the_end: + inflateEnd(&s->zstream); + av_freep(&s->crow_buf); + av_freep(&s->last_row); + av_freep(&s->tmp_row); + return ret; + fail: + ret = -1; + goto the_end; +} + +static av_cold int png_dec_init(AVCodecContext *avctx){ + PNGDecContext *s = avctx->priv_data; + + avcodec_get_frame_defaults(&s->picture); + avctx->coded_frame= &s->picture; + dsputil_init(&s->dsp, avctx); + + return 0; +} + +AVCodec png_decoder = { + "png", + CODEC_TYPE_VIDEO, + CODEC_ID_PNG, + sizeof(PNGDecContext), + png_dec_init, + NULL, + NULL, //decode_end, + decode_frame, + 0 /*CODEC_CAP_DR1*/ /*| CODEC_CAP_DRAW_HORIZ_BAND*/, + NULL, + .long_name = NULL_IF_CONFIG_SMALL("PNG image"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pngenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/pngenc.c new file mode 100644 index 0000000000..f7a1e862d9 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pngenc.c @@ -0,0 +1,449 @@ +/* + * PNG image format + * Copyright (c) 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avcodec.h" +#include "bytestream.h" +#include "dsputil.h" +#include "png.h" + +/* TODO: + * - add 2, 4 and 16 bit depth support + */ + +#include + +//#define DEBUG + +#define IOBUF_SIZE 4096 + +typedef struct PNGEncContext { + DSPContext dsp; + + uint8_t *bytestream; + uint8_t *bytestream_start; + uint8_t *bytestream_end; + AVFrame picture; + + int filter_type; + + z_stream zstream; + uint8_t buf[IOBUF_SIZE]; +} PNGEncContext; + +static void png_get_interlaced_row(uint8_t *dst, int row_size, + int bits_per_pixel, int pass, + const uint8_t *src, int width) +{ + int x, mask, dst_x, j, b, bpp; + uint8_t *d; + const uint8_t *s; + + mask = ff_png_pass_mask[pass]; + switch(bits_per_pixel) { + case 1: + memset(dst, 0, row_size); + dst_x = 0; + for(x = 0; x < width; x++) { + j = (x & 7); + if ((mask << j) & 0x80) { + b = (src[x >> 3] >> (7 - j)) & 1; + dst[dst_x >> 3] |= b << (7 - (dst_x & 7)); + dst_x++; + } + } + break; + default: + bpp = bits_per_pixel >> 3; + d = dst; + s = src; + for(x = 0; x < width; x++) { + j = x & 7; + if ((mask << j) & 0x80) { + memcpy(d, s, bpp); + d += bpp; + } + s += bpp; + } + break; + } +} + +static void sub_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp) +{ + int i; + for(i = 0; i < w; i++) { + int a, b, c, p, pa, pb, pc; + + a = src[i - bpp]; + b = top[i]; + c = top[i - bpp]; + + p = b - c; + pc = a - c; + + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); + + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + dst[i] = src[i] - p; + } +} + +static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type, + uint8_t *src, uint8_t *top, int size, int bpp) +{ + int i; + + switch(filter_type) { + case PNG_FILTER_VALUE_NONE: + memcpy(dst, src, size); + break; + case PNG_FILTER_VALUE_SUB: + dsp->diff_bytes(dst, src, src-bpp, size); + memcpy(dst, src, bpp); + break; + case PNG_FILTER_VALUE_UP: + dsp->diff_bytes(dst, src, top, size); + break; + case PNG_FILTER_VALUE_AVG: + for(i = 0; i < bpp; i++) + dst[i] = src[i] - (top[i] >> 1); + for(; i < size; i++) + dst[i] = src[i] - ((src[i-bpp] + top[i]) >> 1); + break; + case PNG_FILTER_VALUE_PAETH: + for(i = 0; i < bpp; i++) + dst[i] = src[i] - top[i]; + sub_png_paeth_prediction(dst+i, src+i, top+i, size-i, bpp); + break; + } +} + +static uint8_t *png_choose_filter(PNGEncContext *s, uint8_t *dst, + uint8_t *src, uint8_t *top, int size, int bpp) +{ + int pred = s->filter_type; + assert(bpp || !pred); + if(!top && pred) + pred = PNG_FILTER_VALUE_SUB; + if(pred == PNG_FILTER_VALUE_MIXED) { + int i; + int cost, bcost = INT_MAX; + uint8_t *buf1 = dst, *buf2 = dst + size + 16; + for(pred=0; pred<5; pred++) { + png_filter_row(&s->dsp, buf1+1, pred, src, top, size, bpp); + buf1[0] = pred; + cost = 0; + for(i=0; i<=size; i++) + cost += abs((int8_t)buf1[i]); + if(cost < bcost) { + bcost = cost; + FFSWAP(uint8_t*, buf1, buf2); + } + } + return buf2; + } else { + png_filter_row(&s->dsp, dst+1, pred, src, top, size, bpp); + dst[0] = pred; + return dst; + } +} + +static void convert_from_rgb32(uint8_t *dst, const uint8_t *src, int width) +{ + uint8_t *d; + int j; + unsigned int v; + + d = dst; + for(j = 0; j < width; j++) { + v = ((const uint32_t *)src)[j]; + d[0] = v >> 16; + d[1] = v >> 8; + d[2] = v; + d[3] = v >> 24; + d += 4; + } +} + +static void png_write_chunk(uint8_t **f, uint32_t tag, + const uint8_t *buf, int length) +{ + uint32_t crc; + uint8_t tagbuf[4]; + + bytestream_put_be32(f, length); + crc = crc32(0, Z_NULL, 0); + AV_WL32(tagbuf, tag); + crc = crc32(crc, tagbuf, 4); + bytestream_put_be32(f, bswap_32(tag)); + if (length > 0) { + crc = crc32(crc, buf, length); + memcpy(*f, buf, length); + *f += length; + } + bytestream_put_be32(f, crc); +} + +/* XXX: do filtering */ +static int png_write_row(PNGEncContext *s, const uint8_t *data, int size) +{ + int ret; + + s->zstream.avail_in = size; + s->zstream.next_in = (uint8_t *)data; + while (s->zstream.avail_in > 0) { + ret = deflate(&s->zstream, Z_NO_FLUSH); + if (ret != Z_OK) + return -1; + if (s->zstream.avail_out == 0) { + if(s->bytestream_end - s->bytestream > IOBUF_SIZE + 100) + png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE); + s->zstream.avail_out = IOBUF_SIZE; + s->zstream.next_out = s->buf; + } + } + return 0; +} + +static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){ + PNGEncContext *s = avctx->priv_data; + AVFrame *pict = data; + AVFrame * const p= &s->picture; + int bit_depth, color_type, y, len, row_size, ret, is_progressive; + int bits_per_pixel, pass_row_size; + int compression_level; + uint8_t *ptr, *top; + uint8_t *crow_base = NULL, *crow_buf, *crow; + uint8_t *progressive_buf = NULL; + uint8_t *rgba_buf = NULL; + uint8_t *top_buf = NULL; + + *p = *pict; + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + + s->bytestream_start= + s->bytestream= buf; + s->bytestream_end= buf+buf_size; + + is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT); + switch(avctx->pix_fmt) { + case PIX_FMT_RGB32: + bit_depth = 8; + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case PIX_FMT_RGB24: + bit_depth = 8; + color_type = PNG_COLOR_TYPE_RGB; + break; + case PIX_FMT_GRAY8: + bit_depth = 8; + color_type = PNG_COLOR_TYPE_GRAY; + break; + case PIX_FMT_MONOBLACK: + bit_depth = 1; + color_type = PNG_COLOR_TYPE_GRAY; + break; + case PIX_FMT_PAL8: + bit_depth = 8; + color_type = PNG_COLOR_TYPE_PALETTE; + break; + default: + return -1; + } + bits_per_pixel = ff_png_get_nb_channels(color_type) * bit_depth; + row_size = (avctx->width * bits_per_pixel + 7) >> 3; + + s->zstream.zalloc = ff_png_zalloc; + s->zstream.zfree = ff_png_zfree; + s->zstream.opaque = NULL; + compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT ? + Z_DEFAULT_COMPRESSION : + av_clip(avctx->compression_level, 0, 9); + ret = deflateInit2(&s->zstream, compression_level, + Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) + return -1; + crow_base = av_malloc((row_size + 32) << (s->filter_type == PNG_FILTER_VALUE_MIXED)); + if (!crow_base) + goto fail; + crow_buf = crow_base + 15; // pixel data should be aligned, but there's a control byte before it + if (is_progressive) { + progressive_buf = av_malloc(row_size + 1); + if (!progressive_buf) + goto fail; + } + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + rgba_buf = av_malloc(row_size + 1); + if (!rgba_buf) + goto fail; + } + if (is_progressive || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + top_buf = av_malloc(row_size + 1); + if (!top_buf) + goto fail; + } + + /* write png header */ + memcpy(s->bytestream, ff_pngsig, 8); + s->bytestream += 8; + + AV_WB32(s->buf, avctx->width); + AV_WB32(s->buf + 4, avctx->height); + s->buf[8] = bit_depth; + s->buf[9] = color_type; + s->buf[10] = 0; /* compression type */ + s->buf[11] = 0; /* filter type */ + s->buf[12] = is_progressive; /* interlace type */ + + png_write_chunk(&s->bytestream, MKTAG('I', 'H', 'D', 'R'), s->buf, 13); + + /* put the palette if needed */ + if (color_type == PNG_COLOR_TYPE_PALETTE) { + int has_alpha, alpha, i; + unsigned int v; + uint32_t *palette; + uint8_t *alpha_ptr; + + palette = (uint32_t *)p->data[1]; + ptr = s->buf; + alpha_ptr = s->buf + 256 * 3; + has_alpha = 0; + for(i = 0; i < 256; i++) { + v = palette[i]; + alpha = v >> 24; + if (alpha && alpha != 0xff) + has_alpha = 1; + *alpha_ptr++ = alpha; + bytestream_put_be24(&ptr, v); + } + png_write_chunk(&s->bytestream, MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3); + if (has_alpha) { + png_write_chunk(&s->bytestream, MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256); + } + } + + /* now put each row */ + s->zstream.avail_out = IOBUF_SIZE; + s->zstream.next_out = s->buf; + if (is_progressive) { + int pass; + + for(pass = 0; pass < NB_PASSES; pass++) { + /* NOTE: a pass is completely omited if no pixels would be + output */ + pass_row_size = ff_png_pass_row_size(pass, bits_per_pixel, avctx->width); + if (pass_row_size > 0) { + top = NULL; + for(y = 0; y < avctx->height; y++) { + if ((ff_png_pass_ymask[pass] << (y & 7)) & 0x80) { + ptr = p->data[0] + y * p->linesize[0]; + FFSWAP(uint8_t*, progressive_buf, top_buf); + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + convert_from_rgb32(rgba_buf, ptr, avctx->width); + ptr = rgba_buf; + } + png_get_interlaced_row(progressive_buf, pass_row_size, + bits_per_pixel, pass, + ptr, avctx->width); + crow = png_choose_filter(s, crow_buf, progressive_buf, top, pass_row_size, bits_per_pixel>>3); + png_write_row(s, crow, pass_row_size + 1); + top = progressive_buf; + } + } + } + } + } else { + top = NULL; + for(y = 0; y < avctx->height; y++) { + ptr = p->data[0] + y * p->linesize[0]; + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + FFSWAP(uint8_t*, rgba_buf, top_buf); + convert_from_rgb32(rgba_buf, ptr, avctx->width); + ptr = rgba_buf; + } + crow = png_choose_filter(s, crow_buf, ptr, top, row_size, bits_per_pixel>>3); + png_write_row(s, crow, row_size + 1); + top = ptr; + } + } + /* compress last bytes */ + for(;;) { + ret = deflate(&s->zstream, Z_FINISH); + if (ret == Z_OK || ret == Z_STREAM_END) { + len = IOBUF_SIZE - s->zstream.avail_out; + if (len > 0 && s->bytestream_end - s->bytestream > len + 100) { + png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, len); + } + s->zstream.avail_out = IOBUF_SIZE; + s->zstream.next_out = s->buf; + if (ret == Z_STREAM_END) + break; + } else { + goto fail; + } + } + png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0); + + ret = s->bytestream - s->bytestream_start; + the_end: + av_free(crow_base); + av_free(progressive_buf); + av_free(rgba_buf); + av_free(top_buf); + deflateEnd(&s->zstream); + return ret; + fail: + ret = -1; + goto the_end; +} + +static av_cold int png_enc_init(AVCodecContext *avctx){ + PNGEncContext *s = avctx->priv_data; + + avcodec_get_frame_defaults(&s->picture); + avctx->coded_frame= &s->picture; + dsputil_init(&s->dsp, avctx); + + s->filter_type = av_clip(avctx->prediction_method, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED); + if(avctx->pix_fmt == PIX_FMT_MONOBLACK) + s->filter_type = PNG_FILTER_VALUE_NONE; + + return 0; +} + +AVCodec png_encoder = { + "png", + CODEC_TYPE_VIDEO, + CODEC_ID_PNG, + sizeof(PNGEncContext), + png_enc_init, + encode_frame, + NULL, //encode_end, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_PAL8, PIX_FMT_GRAY8, PIX_FMT_MONOBLACK, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("PNG image"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pnm.c b/src/add-ons/media/plugins/avcodec/libavcodec/pnm.c new file mode 100644 index 0000000000..587b703bed --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pnm.c @@ -0,0 +1,147 @@ +/* + * PNM image format + * Copyright (c) 2002, 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avcodec.h" +#include "pnm.h" + +static inline int pnm_space(int c) +{ + return c == ' ' || c == '\n' || c == '\r' || c == '\t'; +} + +static void pnm_get(PNMContext *sc, char *str, int buf_size) +{ + char *s; + int c; + + /* skip spaces and comments */ + for(;;) { + c = *sc->bytestream++; + if (c == '#') { + do { + c = *sc->bytestream++; + } while (c != '\n' && sc->bytestream < sc->bytestream_end); + } else if (!pnm_space(c)) { + break; + } + } + + s = str; + while (sc->bytestream < sc->bytestream_end && !pnm_space(c)) { + if ((s - str) < buf_size - 1) + *s++ = c; + c = *sc->bytestream++; + } + *s = '\0'; +} + +int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s){ + char buf1[32], tuple_type[32]; + int h, w, depth, maxval; + + pnm_get(s, buf1, sizeof(buf1)); + if (!strcmp(buf1, "P4")) { + avctx->pix_fmt = PIX_FMT_MONOWHITE; + } else if (!strcmp(buf1, "P5")) { + if (avctx->codec_id == CODEC_ID_PGMYUV) + avctx->pix_fmt = PIX_FMT_YUV420P; + else + avctx->pix_fmt = PIX_FMT_GRAY8; + } else if (!strcmp(buf1, "P6")) { + avctx->pix_fmt = PIX_FMT_RGB24; + } else if (!strcmp(buf1, "P7")) { + w = -1; + h = -1; + maxval = -1; + depth = -1; + tuple_type[0] = '\0'; + for(;;) { + pnm_get(s, buf1, sizeof(buf1)); + if (!strcmp(buf1, "WIDTH")) { + pnm_get(s, buf1, sizeof(buf1)); + w = strtol(buf1, NULL, 10); + } else if (!strcmp(buf1, "HEIGHT")) { + pnm_get(s, buf1, sizeof(buf1)); + h = strtol(buf1, NULL, 10); + } else if (!strcmp(buf1, "DEPTH")) { + pnm_get(s, buf1, sizeof(buf1)); + depth = strtol(buf1, NULL, 10); + } else if (!strcmp(buf1, "MAXVAL")) { + pnm_get(s, buf1, sizeof(buf1)); + maxval = strtol(buf1, NULL, 10); + } else if (!strcmp(buf1, "TUPLETYPE")) { + pnm_get(s, tuple_type, sizeof(tuple_type)); + } else if (!strcmp(buf1, "ENDHDR")) { + break; + } else { + return -1; + } + } + /* check that all tags are present */ + if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0' || avcodec_check_dimensions(avctx, w, h)) + return -1; + + avctx->width = w; + avctx->height = h; + if (depth == 1) { + if (maxval == 1) + avctx->pix_fmt = PIX_FMT_MONOWHITE; + else + avctx->pix_fmt = PIX_FMT_GRAY8; + } else if (depth == 3) { + avctx->pix_fmt = PIX_FMT_RGB24; + } else if (depth == 4) { + avctx->pix_fmt = PIX_FMT_RGB32; + } else { + return -1; + } + return 0; + } else { + return -1; + } + pnm_get(s, buf1, sizeof(buf1)); + avctx->width = atoi(buf1); + if (avctx->width <= 0) + return -1; + pnm_get(s, buf1, sizeof(buf1)); + avctx->height = atoi(buf1); + if(avcodec_check_dimensions(avctx, avctx->width, avctx->height)) + return -1; + if (avctx->pix_fmt != PIX_FMT_MONOWHITE) { + pnm_get(s, buf1, sizeof(buf1)); + s->maxval = atoi(buf1); + if(s->maxval >= 256 && avctx->pix_fmt == PIX_FMT_GRAY8) { + avctx->pix_fmt = PIX_FMT_GRAY16BE; + if (s->maxval != 65535) + avctx->pix_fmt = PIX_FMT_GRAY16; + } + } + /* more check if YUV420 */ + if (avctx->pix_fmt == PIX_FMT_YUV420P) { + if ((avctx->width & 1) != 0) + return -1; + h = (avctx->height * 2); + if ((h % 3) != 0) + return -1; + h /= 3; + avctx->height = h; + } + return 0; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pnm.h b/src/add-ons/media/plugins/avcodec/libavcodec/pnm.h new file mode 100644 index 0000000000..c77bcca09e --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pnm.h @@ -0,0 +1,37 @@ +/* + * PNM image format + * Copyright (c) 2002, 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FFMPEG_PNM_H +#define FFMPEG_PNM_H + +#include "avcodec.h" + +typedef struct PNMContext { + uint8_t *bytestream; + uint8_t *bytestream_start; + uint8_t *bytestream_end; + AVFrame picture; + int maxval; ///< maximum value of a pixel +} PNMContext; + +int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s); + +#endif /* FFMPEG_PNM_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pnm_parser.c b/src/add-ons/media/plugins/avcodec/libavcodec/pnm_parser.c new file mode 100644 index 0000000000..f5212f0244 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pnm_parser.c @@ -0,0 +1,93 @@ +/* + * PNM image parser + * Copyright (c) 2002, 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "parser.h" //for ParseContext +#include "pnm.h" + + +static int pnm_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + ParseContext *pc = s->priv_data; + PNMContext pnmctx; + int next; + + for(; pc->overread>0; pc->overread--){ + pc->buffer[pc->index++]= pc->buffer[pc->overread_index++]; + } +retry: + if(pc->index){ + pnmctx.bytestream_start= + pnmctx.bytestream= pc->buffer; + pnmctx.bytestream_end= pc->buffer + pc->index; + }else{ + pnmctx.bytestream_start= + pnmctx.bytestream= (uint8_t *) buf; /* casts avoid warnings */ + pnmctx.bytestream_end= (uint8_t *) buf + buf_size; + } + if(ff_pnm_decode_header(avctx, &pnmctx) < 0){ + if(pnmctx.bytestream < pnmctx.bytestream_end){ + if(pc->index){ + pc->index=0; + }else{ + buf++; + buf_size--; + } + goto retry; + } +#if 0 + if(pc->index && pc->index*2 + FF_INPUT_BUFFER_PADDING_SIZE < pc->buffer_size && buf_size > pc->index){ + memcpy(pc->buffer + pc->index, buf, pc->index); + pc->index += pc->index; + buf += pc->index; + buf_size -= pc->index; + goto retry; + } +#endif + next= END_NOT_FOUND; + }else{ + next= pnmctx.bytestream - pnmctx.bytestream_start + + avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height); + if(pnmctx.bytestream_start!=buf) + next-= pc->index; + if(next > buf_size) + next= END_NOT_FOUND; + } + + if(ff_combine_frame(pc, next, &buf, &buf_size)<0){ + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +AVCodecParser pnm_parser = { + { CODEC_ID_PGM, CODEC_ID_PGMYUV, CODEC_ID_PPM, CODEC_ID_PBM, CODEC_ID_PAM}, + sizeof(ParseContext), + NULL, + pnm_parse, + ff_parse_close, +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pnmenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/pnmenc.c new file mode 100644 index 0000000000..b62ea759df --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pnmenc.c @@ -0,0 +1,430 @@ +/* + * PNM image format + * Copyright (c) 2002, 2003 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avcodec.h" +#include "bytestream.h" +#include "pnm.h" + + +static av_cold int common_init(AVCodecContext *avctx){ + PNMContext *s = avctx->priv_data; + + avcodec_get_frame_defaults((AVFrame*)&s->picture); + avctx->coded_frame= (AVFrame*)&s->picture; + + return 0; +} + +static int pnm_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + PNMContext * const s = avctx->priv_data; + AVFrame *picture = data; + AVFrame * const p= (AVFrame*)&s->picture; + int i, n, linesize, h, upgrade = 0; + unsigned char *ptr; + + s->bytestream_start= + s->bytestream= buf; + s->bytestream_end= buf + buf_size; + + if(ff_pnm_decode_header(avctx, s) < 0) + return -1; + + if(p->data[0]) + avctx->release_buffer(avctx, p); + + p->reference= 0; + if(avctx->get_buffer(avctx, p) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + + switch(avctx->pix_fmt) { + default: + return -1; + case PIX_FMT_RGB24: + n = avctx->width * 3; + goto do_read; + case PIX_FMT_GRAY8: + n = avctx->width; + if (s->maxval < 255) + upgrade = 1; + goto do_read; + case PIX_FMT_GRAY16BE: + case PIX_FMT_GRAY16LE: + n = avctx->width * 2; + if (s->maxval < 65535) + upgrade = 2; + goto do_read; + case PIX_FMT_MONOWHITE: + case PIX_FMT_MONOBLACK: + n = (avctx->width + 7) >> 3; + do_read: + ptr = p->data[0]; + linesize = p->linesize[0]; + if(s->bytestream + n*avctx->height > s->bytestream_end) + return -1; + for(i = 0; i < avctx->height; i++) { + if (!upgrade) + memcpy(ptr, s->bytestream, n); + else if (upgrade == 1) { + unsigned int j, f = (255*128 + s->maxval/2) / s->maxval; + for (j=0; jbytestream[j] * f + 64) >> 7; + } else if (upgrade == 2) { + unsigned int j, v, f = (65535*32768 + s->maxval/2) / s->maxval; + for (j=0; jbytestream)[j]); + ((uint16_t *)ptr)[j] = (v * f + 16384) >> 15; + } + } + s->bytestream += n; + ptr += linesize; + } + break; + case PIX_FMT_YUV420P: + { + unsigned char *ptr1, *ptr2; + + n = avctx->width; + ptr = p->data[0]; + linesize = p->linesize[0]; + if(s->bytestream + n*avctx->height*3/2 > s->bytestream_end) + return -1; + for(i = 0; i < avctx->height; i++) { + memcpy(ptr, s->bytestream, n); + s->bytestream += n; + ptr += linesize; + } + ptr1 = p->data[1]; + ptr2 = p->data[2]; + n >>= 1; + h = avctx->height >> 1; + for(i = 0; i < h; i++) { + memcpy(ptr1, s->bytestream, n); + s->bytestream += n; + memcpy(ptr2, s->bytestream, n); + s->bytestream += n; + ptr1 += p->linesize[1]; + ptr2 += p->linesize[2]; + } + } + break; + case PIX_FMT_RGB32: + ptr = p->data[0]; + linesize = p->linesize[0]; + if(s->bytestream + avctx->width*avctx->height*4 > s->bytestream_end) + return -1; + for(i = 0; i < avctx->height; i++) { + int j, r, g, b, a; + + for(j = 0;j < avctx->width; j++) { + r = *s->bytestream++; + g = *s->bytestream++; + b = *s->bytestream++; + a = *s->bytestream++; + ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b; + } + ptr += linesize; + } + break; + } + *picture= *(AVFrame*)&s->picture; + *data_size = sizeof(AVPicture); + + return s->bytestream - s->bytestream_start; +} + +static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){ + PNMContext *s = avctx->priv_data; + AVFrame *pict = data; + AVFrame * const p= (AVFrame*)&s->picture; + int i, h, h1, c, n, linesize; + uint8_t *ptr, *ptr1, *ptr2; + + if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){ + av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n"); + return -1; + } + + *p = *pict; + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + + s->bytestream_start= + s->bytestream= outbuf; + s->bytestream_end= outbuf+buf_size; + + h = avctx->height; + h1 = h; + switch(avctx->pix_fmt) { + case PIX_FMT_MONOWHITE: + c = '4'; + n = (avctx->width + 7) >> 3; + break; + case PIX_FMT_GRAY8: + c = '5'; + n = avctx->width; + break; + case PIX_FMT_GRAY16BE: + c = '5'; + n = avctx->width * 2; + break; + case PIX_FMT_RGB24: + c = '6'; + n = avctx->width * 3; + break; + case PIX_FMT_YUV420P: + c = '5'; + n = avctx->width; + h1 = (h * 3) / 2; + break; + default: + return -1; + } + snprintf(s->bytestream, s->bytestream_end - s->bytestream, + "P%c\n%d %d\n", + c, avctx->width, h1); + s->bytestream += strlen(s->bytestream); + if (avctx->pix_fmt != PIX_FMT_MONOWHITE) { + snprintf(s->bytestream, s->bytestream_end - s->bytestream, + "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE) ? 255 : 65535); + s->bytestream += strlen(s->bytestream); + } + + ptr = p->data[0]; + linesize = p->linesize[0]; + for(i=0;ibytestream, ptr, n); + s->bytestream += n; + ptr += linesize; + } + + if (avctx->pix_fmt == PIX_FMT_YUV420P) { + h >>= 1; + n >>= 1; + ptr1 = p->data[1]; + ptr2 = p->data[2]; + for(i=0;ibytestream, ptr1, n); + s->bytestream += n; + memcpy(s->bytestream, ptr2, n); + s->bytestream += n; + ptr1 += p->linesize[1]; + ptr2 += p->linesize[2]; + } + } + return s->bytestream - s->bytestream_start; +} + +static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){ + PNMContext *s = avctx->priv_data; + AVFrame *pict = data; + AVFrame * const p= (AVFrame*)&s->picture; + int i, h, w, n, linesize, depth, maxval; + const char *tuple_type; + uint8_t *ptr; + + if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){ + av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n"); + return -1; + } + + *p = *pict; + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + + s->bytestream_start= + s->bytestream= outbuf; + s->bytestream_end= outbuf+buf_size; + + h = avctx->height; + w = avctx->width; + switch(avctx->pix_fmt) { + case PIX_FMT_MONOWHITE: + n = (w + 7) >> 3; + depth = 1; + maxval = 1; + tuple_type = "BLACKANDWHITE"; + break; + case PIX_FMT_GRAY8: + n = w; + depth = 1; + maxval = 255; + tuple_type = "GRAYSCALE"; + break; + case PIX_FMT_RGB24: + n = w * 3; + depth = 3; + maxval = 255; + tuple_type = "RGB"; + break; + case PIX_FMT_RGB32: + n = w * 4; + depth = 4; + maxval = 255; + tuple_type = "RGB_ALPHA"; + break; + default: + return -1; + } + snprintf(s->bytestream, s->bytestream_end - s->bytestream, + "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n", + w, h, depth, maxval, tuple_type); + s->bytestream += strlen(s->bytestream); + + ptr = p->data[0]; + linesize = p->linesize[0]; + + if (avctx->pix_fmt == PIX_FMT_RGB32) { + int j; + unsigned int v; + + for(i=0;ibytestream, v); + *s->bytestream++ = v >> 24; + } + ptr += linesize; + } + } else { + for(i=0;ibytestream, ptr, n); + s->bytestream += n; + ptr += linesize; + } + } + return s->bytestream - s->bytestream_start; +} + +#if 0 +static int pnm_probe(AVProbeData *pd) +{ + const char *p = pd->buf; + if (pd->buf_size >= 8 && + p[0] == 'P' && + p[1] >= '4' && p[1] <= '6' && + pnm_space(p[2]) ) + return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */ + else + return 0; +} + +static int pgmyuv_probe(AVProbeData *pd) +{ + if (match_ext(pd->filename, "pgmyuv")) + return AVPROBE_SCORE_MAX; + else + return 0; +} + +static int pam_probe(AVProbeData *pd) +{ + const char *p = pd->buf; + if (pd->buf_size >= 8 && + p[0] == 'P' && + p[1] == '7' && + p[2] == '\n') + return AVPROBE_SCORE_MAX; + else + return 0; +} +#endif + + +#ifdef CONFIG_PGM_ENCODER +AVCodec pgm_encoder = { + "pgm", + CODEC_TYPE_VIDEO, + CODEC_ID_PGM, + sizeof(PNMContext), + common_init, + pnm_encode_frame, + NULL, //encode_end, + pnm_decode_frame, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"), +}; +#endif // CONFIG_PGM_ENCODER + +#ifdef CONFIG_PGMYUV_ENCODER +AVCodec pgmyuv_encoder = { + "pgmyuv", + CODEC_TYPE_VIDEO, + CODEC_ID_PGMYUV, + sizeof(PNMContext), + common_init, + pnm_encode_frame, + NULL, //encode_end, + pnm_decode_frame, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"), +}; +#endif // CONFIG_PGMYUV_ENCODER + +#ifdef CONFIG_PPM_ENCODER +AVCodec ppm_encoder = { + "ppm", + CODEC_TYPE_VIDEO, + CODEC_ID_PPM, + sizeof(PNMContext), + common_init, + pnm_encode_frame, + NULL, //encode_end, + pnm_decode_frame, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"), +}; +#endif // CONFIG_PPM_ENCODER + +#ifdef CONFIG_PBM_ENCODER +AVCodec pbm_encoder = { + "pbm", + CODEC_TYPE_VIDEO, + CODEC_ID_PBM, + sizeof(PNMContext), + common_init, + pnm_encode_frame, + NULL, //encode_end, + pnm_decode_frame, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"), +}; +#endif // CONFIG_PBM_ENCODER + +#ifdef CONFIG_PAM_ENCODER +AVCodec pam_encoder = { + "pam", + CODEC_TYPE_VIDEO, + CODEC_ID_PAM, + sizeof(PNMContext), + common_init, + pam_encode_frame, + NULL, //encode_end, + pnm_decode_frame, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"), +}; +#endif // CONFIG_PAM_ENCODER diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/pthread.c b/src/add-ons/media/plugins/avcodec/libavcodec/pthread.c new file mode 100644 index 0000000000..702adb533d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/pthread.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2004 Roman Shaposhnik. + * + * Many thanks to Steven M. Schultz for providing clever ideas and + * to Michael Niedermayer for writing initial + * implementation. + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "avcodec.h" + +typedef int (action_t)(AVCodecContext *c, void *arg); + +typedef struct ThreadContext { + pthread_t *workers; + action_t *func; + void **args; + int *rets; + int rets_count; + int job_count; + + pthread_cond_t last_job_cond; + pthread_cond_t current_job_cond; + pthread_mutex_t current_job_lock; + int current_job; + int done; +} ThreadContext; + +static void* attribute_align_arg worker(void *v) +{ + AVCodecContext *avctx = v; + ThreadContext *c = avctx->thread_opaque; + int our_job = c->job_count; + int thread_count = avctx->thread_count; + int self_id; + + pthread_mutex_lock(&c->current_job_lock); + self_id = c->current_job++; + for (;;){ + while (our_job >= c->job_count) { + if (c->current_job == thread_count + c->job_count) + pthread_cond_signal(&c->last_job_cond); + + pthread_cond_wait(&c->current_job_cond, &c->current_job_lock); + our_job = self_id; + + if (c->done) { + pthread_mutex_unlock(&c->current_job_lock); + return NULL; + } + } + pthread_mutex_unlock(&c->current_job_lock); + + c->rets[our_job%c->rets_count] = c->func(avctx, c->args[our_job]); + + pthread_mutex_lock(&c->current_job_lock); + our_job = c->current_job++; + } +} + +static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count) +{ + pthread_cond_wait(&c->last_job_cond, &c->current_job_lock); + pthread_mutex_unlock(&c->current_job_lock); +} + +void avcodec_thread_free(AVCodecContext *avctx) +{ + ThreadContext *c = avctx->thread_opaque; + int i; + + pthread_mutex_lock(&c->current_job_lock); + c->done = 1; + pthread_cond_broadcast(&c->current_job_cond); + pthread_mutex_unlock(&c->current_job_lock); + + for (i=0; ithread_count; i++) + pthread_join(c->workers[i], NULL); + + pthread_mutex_destroy(&c->current_job_lock); + pthread_cond_destroy(&c->current_job_cond); + pthread_cond_destroy(&c->last_job_cond); + av_free(c->workers); + av_freep(&avctx->thread_opaque); +} + +int avcodec_thread_execute(AVCodecContext *avctx, action_t* func, void **arg, int *ret, int job_count) +{ + ThreadContext *c= avctx->thread_opaque; + int dummy_ret; + + if (job_count <= 0) + return 0; + + pthread_mutex_lock(&c->current_job_lock); + + c->current_job = avctx->thread_count; + c->job_count = job_count; + c->args = arg; + c->func = func; + if (ret) { + c->rets = ret; + c->rets_count = job_count; + } else { + c->rets = &dummy_ret; + c->rets_count = 1; + } + pthread_cond_broadcast(&c->current_job_cond); + + avcodec_thread_park_workers(c, avctx->thread_count); + + return 0; +} + +int avcodec_thread_init(AVCodecContext *avctx, int thread_count) +{ + int i; + ThreadContext *c; + + c = av_mallocz(sizeof(ThreadContext)); + if (!c) + return -1; + + c->workers = av_mallocz(sizeof(pthread_t)*thread_count); + if (!c->workers) { + av_free(c); + return -1; + } + + avctx->thread_opaque = c; + avctx->thread_count = thread_count; + c->current_job = 0; + c->job_count = 0; + c->done = 0; + pthread_cond_init(&c->current_job_cond, NULL); + pthread_cond_init(&c->last_job_cond, NULL); + pthread_mutex_init(&c->current_job_lock, NULL); + pthread_mutex_lock(&c->current_job_lock); + for (i=0; iworkers[i], NULL, worker, avctx)) { + avctx->thread_count = i; + pthread_mutex_unlock(&c->current_job_lock); + avcodec_thread_free(avctx); + return -1; + } + } + + avcodec_thread_park_workers(c, thread_count); + + avctx->execute = avcodec_thread_execute; + return 0; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/ptx.c b/src/add-ons/media/plugins/avcodec/libavcodec/ptx.c new file mode 100644 index 0000000000..79424b9c42 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/ptx.c @@ -0,0 +1,118 @@ +/* + * V.Flash PTX (.ptx) image decoder + * Copyright (c) 2007 Ivo van Poorten + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" + +typedef struct PTXContext { + AVFrame picture; +} PTXContext; + +static av_cold int ptx_init(AVCodecContext *avctx) { + PTXContext *s = avctx->priv_data; + + avcodec_get_frame_defaults(&s->picture); + avctx->coded_frame= &s->picture; + + return 0; +} + +static int ptx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, + const uint8_t *buf, int buf_size) { + PTXContext * const s = avctx->priv_data; + AVFrame *picture = data; + AVFrame * const p = &s->picture; + unsigned int offset, w, h, y, stride, bytes_per_pixel; + uint8_t *ptr; + + offset = AV_RL16(buf); + w = AV_RL16(buf+8); + h = AV_RL16(buf+10); + bytes_per_pixel = AV_RL16(buf+12) >> 3; + + if (bytes_per_pixel != 2) { + av_log(avctx, AV_LOG_ERROR, "image format is not rgb15, please report on ffmpeg-users mailing list\n"); + return -1; + } + + avctx->pix_fmt = PIX_FMT_RGB555; + + if (offset != 0x2c) + av_log(avctx, AV_LOG_WARNING, "offset != 0x2c, untested due to lack of sample files\n"); + + buf += offset; + + if (p->data[0]) + avctx->release_buffer(avctx, p); + + if (avcodec_check_dimensions(avctx, w, h)) + return -1; + if (w != avctx->width || h != avctx->height) + avcodec_set_dimensions(avctx, w, h); + if (avctx->get_buffer(avctx, p) < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + + p->pict_type = FF_I_TYPE; + + ptr = p->data[0]; + stride = p->linesize[0]; + + for (y=0; ypicture; + *data_size = sizeof(AVPicture); + + return offset + w*h*bytes_per_pixel; +} + +static av_cold int ptx_end(AVCodecContext *avctx) { + PTXContext *s = avctx->priv_data; + + if(s->picture.data[0]) + avctx->release_buffer(avctx, &s->picture); + + return 0; +} + +AVCodec ptx_decoder = { + "ptx", + CODEC_TYPE_VIDEO, + CODEC_ID_PTX, + sizeof(PTXContext), + ptx_init, + NULL, + ptx_end, + ptx_decode_frame, + 0, + NULL, + .long_name = NULL_IF_CONFIG_SMALL("V.Flash PTX image"), +};