FFmpeg-soc
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
June 2007
- 14 participants
- 87 discussions
Author: marco
Date: Sun Jun 10 16:17:50 2007
New Revision: 243
Log:
Add Dirac parser
Added:
dirac/dirac_parser.c
Added: dirac/dirac_parser.c
==============================================================================
--- (empty file)
+++ dirac/dirac_parser.c Sun Jun 10 16:17:50 2007
@@ -0,0 +1,94 @@
+/*
+ * Dirac parser
+ *
+ * Copyright (c) 2007 Marco Gerards <marco(a)gnu.org>
+ *
+ * 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"
+
+#define DEBUG 1
+
+/**
+ * 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 find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size){
+ uint32_t state;
+
+ /* Check if there is enough room for a Parse Info Header,
+ otherwise stop. */
+ if (buf_size < 13)
+ return END_NOT_FOUND;
+
+ state = pc->state;
+
+ if (pc->frame_start_found == 0) {
+ /* next_parse_offset has the amount of bytes to the next frame. */
+ state = AV_RB32(buf + 5);
+ }
+
+ if (state > buf_size) {
+ /* The frame is not yet complete, use the state to store how
+ many bytes have to be read. */
+ state -= buf_size;
+ } else {
+ pc->frame_start_found = 0;
+ pc->state = 0;
+
+ return state;
+ }
+
+ pc->frame_start_found = 1;
+ pc->state = state;
+
+ return END_NOT_FOUND;
+}
+
+static int dirac_parse(AVCodecParserContext *s,
+ AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ ParseContext *pc = s->priv_data;
+ int next;
+
+ if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){
+ next= buf_size;
+ }else{
+ next= find_frame_end(pc, buf, buf_size);
+
+ 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 dirac_parser = {
+ { CODEC_ID_DIRAC },
+ sizeof(ParseContext),
+ NULL,
+ dirac_parse,
+ ff_parse_close,
+};
5
6
Author: conrad
Date: Mon Jun 25 02:24:04 2007
New Revision: 279
Log:
Write the Seek Head element
Modified:
matroska/matroskaenc.c
Modified: matroska/matroskaenc.c
==============================================================================
--- matroska/matroskaenc.c (original)
+++ matroska/matroskaenc.c Mon Jun 25 02:24:04 2007
@@ -24,12 +24,29 @@
#include "xiph.h"
#include "matroska.h"
+typedef struct mkv_seekhead_entry {
+ unsigned int elementid;
+ uint64_t segmentpos;
+} mkv_seekhead_entry;
+
+typedef struct mkv_seekhead {
+ offset_t filepos;
+ offset_t segment_offset; // the file offset to the beginning of the segment
+ int reserved_size; // -1 if appending to file
+ int max_entries;
+ mkv_seekhead_entry *entries;
+ int num_entries;
+} mkv_seekhead;
+
typedef struct MatroskaMuxContext {
offset_t segment;
+ offset_t segment_offset;
offset_t cluster;
uint64_t cluster_pts;
offset_t duration_offset;
uint64_t duration;
+ mkv_seekhead *main_seekhead;
+ mkv_seekhead *cluster_seekhead;
} MatroskaMuxContext;
static void put_ebml_id(ByteIOContext *pb, unsigned int id)
@@ -43,6 +60,17 @@ static void put_ebml_id(ByteIOContext *p
put_byte(pb, id);
}
+static int ebml_id_size(unsigned int id)
+{
+ if (id >= 0x3fffff)
+ return 4;
+ if (id >= 0x7fff)
+ return 3;
+ if (id >= 0xff)
+ return 2;
+ return 1;
+}
+
// XXX: test this thoroughly and get rid of minbytes hack (currently needed to
// use up all of the space reserved in start_ebml_master)
static void put_ebml_size(ByteIOContext *pb, uint64_t size, int minbytes)
@@ -128,6 +156,91 @@ static void end_ebml_master(ByteIOContex
url_fseek(pb, pos, SEEK_SET);
}
+// initializes a mkv_seekhead element to be ready to index level 1 matroska elements
+// if numelements is greater than 0, it reserves enough space for that many elements
+// at the current file position and writes the seekhead there, otherwise the seekhead
+// will be appended to the file when end_mkv_seekhead() is called
+static mkv_seekhead * mkv_start_seekhead(ByteIOContext *pb, offset_t segment_offset, int numelements)
+{
+ mkv_seekhead *new_seekhead = av_mallocz(sizeof(mkv_seekhead));
+ if (new_seekhead == NULL)
+ return NULL;
+
+ new_seekhead->segment_offset = segment_offset;
+
+ if (numelements > 0) {
+ new_seekhead->filepos = url_ftell(pb);
+ // 21 bytes max for a seek entry, 10 bytes max for the SeekHead ID and size,
+ // and 3 bytes to guarantee that an EBML void element will fit afterwards
+ // XXX: 28 bytes right now because begin_ebml_master() reserves more than necessary
+ new_seekhead->reserved_size = numelements * 28 + 13;
+ new_seekhead->max_entries = numelements;
+ put_ebml_void(pb, new_seekhead->reserved_size);
+ }
+ return new_seekhead;
+}
+
+static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid, uint64_t filepos)
+{
+ mkv_seekhead_entry *entries = seekhead->entries;
+ int new_entry = seekhead->num_entries;
+
+ // don't store more elements than we reserved space for
+ if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries)
+ return -1;
+
+ entries = av_realloc(entries, (seekhead->num_entries + 1) * sizeof(mkv_seekhead_entry));
+ if (entries == NULL)
+ return -1;
+
+ entries[new_entry].elementid = elementid;
+ entries[new_entry].segmentpos = filepos - seekhead->segment_offset;
+
+ seekhead->entries = entries;
+ seekhead->num_entries++;
+
+ return 0;
+}
+
+// returns the file offset where the seekhead was written and frees the seekhead
+static offset_t mkv_write_seekhead(ByteIOContext *pb, mkv_seekhead *seekhead)
+{
+ offset_t metaseek, seekentry, currentpos;
+ int i;
+
+ currentpos = url_ftell(pb);
+
+ if (seekhead->reserved_size > 0)
+ url_fseek(pb, seekhead->filepos, SEEK_SET);
+
+ metaseek = start_ebml_master(pb, MATROSKA_ID_SEEKHEAD);
+ for (i = 0; i < seekhead->num_entries; i++) {
+ mkv_seekhead_entry *entry = &seekhead->entries[i];
+
+ seekentry = start_ebml_master(pb, MATROSKA_ID_SEEKENTRY);
+
+ put_ebml_id(pb, MATROSKA_ID_SEEKID);
+ put_ebml_size(pb, ebml_id_size(entry->elementid), 0);
+ put_ebml_id(pb, entry->elementid);
+
+ put_ebml_uint(pb, MATROSKA_ID_SEEKPOSITION, entry->segmentpos);
+ end_ebml_master(pb, seekentry);
+ }
+ end_ebml_master(pb, metaseek);
+
+ if (seekhead->reserved_size > 0) {
+ uint64_t remaining = seekhead->filepos + seekhead->reserved_size - url_ftell(pb);
+ put_ebml_void(pb, remaining);
+ url_fseek(pb, currentpos, SEEK_SET);
+
+ currentpos = seekhead->filepos;
+ }
+ av_free(seekhead->entries);
+ av_free(seekhead);
+
+ return currentpos;
+}
+
static int put_xiph_codecpriv(ByteIOContext *pb, AVCodecContext *codec)
{
offset_t codecprivate;
@@ -168,6 +281,9 @@ static int mkv_write_tracks(AVFormatCont
offset_t tracks;
int i, j;
+ if (mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TRACKS, url_ftell(pb)) < 0)
+ return -1;
+
tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS);
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
@@ -267,6 +383,17 @@ static int mkv_write_header(AVFormatCont
end_ebml_master(pb, ebml_header);
mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT);
+ mkv->segment_offset = url_ftell(pb);
+
+ // we write 2 seek heads - one at the end of the file to point to each cluster, and
+ // one at the beginning to point to all other level one elements (including the seek
+ // head at the end of the file), which isn't more than 10 elements if we only write one
+ // of each other currently defined level 1 element
+ mkv->main_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10);
+ mkv->cluster_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 0);
+
+ if (mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_INFO, url_ftell(pb)) < 0)
+ return -1;
segment_info = start_ebml_master(pb, MATROSKA_ID_INFO);
put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000);
@@ -287,6 +414,9 @@ static int mkv_write_header(AVFormatCont
if (mkv_write_tracks(s) < 0)
return -1;
+ if (mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb)) < 0)
+ return -1;
+
mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER);
put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, 0);
mkv->cluster_pts = 0;
@@ -303,6 +433,10 @@ static int mkv_write_packet(AVFormatCont
// start a new cluster every 5 MB or 5 sec
if (url_ftell(pb) > mkv->cluster + 5*1024*1024 || pkt->pts > mkv->cluster_pts + 5000) {
end_ebml_master(pb, mkv->cluster);
+
+ if (mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb)) < 0)
+ return -1;
+
mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER);
put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, pkt->pts);
mkv->cluster_pts = pkt->pts;
@@ -323,10 +457,14 @@ static int mkv_write_trailer(AVFormatCon
{
MatroskaMuxContext *mkv = s->priv_data;
ByteIOContext *pb = &s->pb;
- offset_t currentpos;
+ offset_t currentpos, second_seekhead;
end_ebml_master(pb, mkv->cluster);
+ second_seekhead = mkv_write_seekhead(pb, mkv->cluster_seekhead);
+ mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_SEEKHEAD, second_seekhead);
+ mkv_write_seekhead(pb, mkv->main_seekhead);
+
// update the duration
currentpos = url_ftell(pb);
url_fseek(pb, mkv->duration_offset, SEEK_SET);
3
4
Author: conrad
Date: Mon Jun 25 02:14:49 2007
New Revision: 271
Log:
>From the specs, track number and UID only have to be nonzer, so use stream_index + 1 for both
Modified:
matroska/matroskaenc.c
Modified: matroska/matroskaenc.c
==============================================================================
--- matroska/matroskaenc.c (original)
+++ matroska/matroskaenc.c Mon Jun 25 02:14:49 2007
@@ -149,10 +149,8 @@ static int mkv_write_header(AVFormatCont
int native_id = 0;
track = start_ebml_master(pb, MATROSKA_ID_TRACKENTRY);
- put_ebml_uint (pb, MATROSKA_ID_TRACKNUMBER , i);
- // XXX: random number for UID? and can we use the same UID when copying
- // from another MKV as the specs recommend?
- put_ebml_uint (pb, MATROSKA_ID_TRACKUID , i);
+ put_ebml_uint (pb, MATROSKA_ID_TRACKNUMBER , i + 1);
+ put_ebml_uint (pb, MATROSKA_ID_TRACKUID , i + 1);
put_ebml_uint (pb, MATROSKA_ID_TRACKFLAGLACING , 0); // no lacing (yet)
if (st->language[0])
@@ -270,7 +268,7 @@ static int mkv_write_packet(AVFormatCont
}
block = start_ebml_master(pb, MATROSKA_ID_SIMPLEBLOCK);
- put_byte(pb, 0x80 | pkt->stream_index); // this assumes stream_index is less than 127
+ put_byte(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126
put_be16(pb, pkt->pts - mkv->cluster_pts);
put_byte(pb, !!(pkt->flags & PKT_FLAG_KEY));
put_buffer(pb, pkt->data, pkt->size);
4
3
05 Jul '07
Author: k.nowosad
Date: Mon Jun 25 12:28:41 2007
New Revision: 282
Log:
The basics of encoder. Quantization, dwt 9-7 and some smaller features will be added.
Added:
jpeg2000/checkout.sh (contents, props changed)
jpeg2000/ffmpeg.patch
jpeg2000/j2k.h
jpeg2000/j2kenc.c
Added: jpeg2000/checkout.sh
==============================================================================
--- (empty file)
+++ jpeg2000/checkout.sh Mon Jun 25 12:28:41 2007
@@ -0,0 +1,9 @@
+echo "checking out ffmpeg svn"
+svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk/ ffmpeg
+echo "patching ffmpeg"
+cd ffmpeg/libavcodec ;
+patch -p0 <../../ffmpeg.patch
+echo "copying the jpeg2000 files to ffmpeg/libavcodec"
+ln -s ../../j2kenc.c j2kenc.c
+ln -s ../../j2k.h j2k.h
+echo "Done, now just do a regular configure and make to build."
Added: jpeg2000/ffmpeg.patch
==============================================================================
--- (empty file)
+++ jpeg2000/ffmpeg.patch Mon Jun 25 12:28:41 2007
@@ -0,0 +1,36 @@
+Index: Makefile
+===================================================================
+--- Makefile (wersja 9417)
++++ Makefile (kopia robocza)
+@@ -93,6 +93,7 @@
+ OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o
+ OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o
+ OBJS-$(CONFIG_INTERPLAY_DPCM_DECODER) += dpcm.o
++OBJS-$(CONFIG_JPEG2000_ENCODER) += j2kenc.o
+ OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o mjpegdec.o mjpeg.o golomb.o
+ OBJS-$(CONFIG_JPEGLS_ENCODER) += jpeglsenc.o jpegls.o golomb.o
+ OBJS-$(CONFIG_KMVC_DECODER) += kmvc.o
+Index: allcodecs.c
+===================================================================
+--- allcodecs.c (wersja 9417)
++++ allcodecs.c (kopia robocza)
+@@ -92,6 +92,7 @@
+ REGISTER_DECODER(INDEO3, indeo3);
+ REGISTER_DECODER(INTERPLAY_VIDEO, interplay_video);
+ REGISTER_ENCDEC (JPEGLS, jpegls);
++ REGISTER_ENCODER(JPEG2000, jpeg2000);
+ REGISTER_DECODER(KMVC, kmvc);
+ REGISTER_ENCODER(LIBX264, libx264);
+ REGISTER_ENCODER(LIBXVID, libxvid);
+Index: allcodecs.h
+===================================================================
+--- allcodecs.h (wersja 9417)
++++ allcodecs.h (kopia robocza)
+@@ -40,6 +40,7 @@
+ extern AVCodec h264_encoder;
+ extern AVCodec huffyuv_encoder;
+ extern AVCodec jpegls_encoder;
++extern AVCodec jpeg2000_encoder;
+ extern AVCodec ljpeg_encoder;
+ extern AVCodec mdec_encoder;
+ extern AVCodec mjpeg_encoder;
Added: jpeg2000/j2k.h
==============================================================================
--- (empty file)
+++ jpeg2000/j2k.h Mon Jun 25 12:28:41 2007
@@ -0,0 +1,163 @@
+/*
+ * JPEG2000 tables
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ *
+ */
+
+/**
+ * JPEG2000 tables
+ * @file j2k.h
+ * @author Kamil Nowosad
+ */
+
+#ifndef _J2K_H_
+#define _J2K_H_
+
+enum J2kMarkers{
+ J2K_SOC = 0xff4f,
+ J2K_SIZ = 0xff51,
+ J2K_COD,
+ J2K_COC,
+ J2K_TLM = 0xff55,
+ J2K_PLM = 0xff57,
+ J2K_PLT,
+ J2K_QCD = 0xff5c,
+ J2K_QCC,
+ J2K_RGN,
+ J2K_POC,
+ J2K_PPM,
+ J2K_PPT,
+ J2K_CRG,
+ J2K_COM,
+ J2K_SOT = 0xff90,
+ J2K_SOP,
+ J2K_EPH,
+ J2K_SOD,
+ J2K_EOC = 0xffd9,
+};
+
+
+/* arithmetic entropy coder context */
+//TODO: optimize [nice solution in openjpeg]
+typedef struct {
+ unsigned int qe;
+ unsigned int nmps;
+ unsigned int nlps;
+ unsigned int sw;
+} J2kAecState;
+
+const static J2kAecState aec_cx_states[47] = {
+ {0x5601, 1, 1, 1},
+ {0x3401, 2, 6, 0},
+ {0x1801, 3, 9, 0},
+ {0x0AC1, 4, 12, 0},
+ {0x0521, 5, 29, 0},
+ {0x0221, 38, 33, 0},
+ {0x5601, 7, 6, 1},
+ {0x5401, 8, 14, 0},
+ {0x4801, 9, 14, 0},
+ {0x3801, 10, 14, 0},
+ {0x3001, 11, 17, 0},
+ {0x2401, 12, 18, 0},
+ {0x1C01, 13, 20, 0},
+ {0x1601, 29, 21, 0},
+ {0x5601, 15, 14, 1},
+ {0x5401, 16, 14, 0},
+ {0x5101, 17, 15, 0},
+ {0x4801, 18, 16, 0},
+ {0x3801, 19, 17, 0},
+ {0x3401, 20, 18, 0},
+ {0x3001, 21, 19, 0},
+ {0x2801, 22, 19, 0},
+ {0x2401, 23, 20, 0},
+ {0x2201, 24, 21, 0},
+ {0x1C01, 25, 22, 0},
+ {0x1801, 26, 23, 0},
+ {0x1601, 27, 24, 0},
+ {0x1401, 28, 25, 0},
+ {0x1201, 29, 26, 0},
+ {0x1101, 30, 27, 0},
+ {0x0AC1, 31, 28, 0},
+ {0x09C1, 32, 29, 0},
+ {0x08A1, 33, 30, 0},
+ {0x0521, 34, 31, 0},
+ {0x0441, 35, 32, 0},
+ {0x02A1, 36, 33, 0},
+ {0x0221, 37, 34, 0},
+ {0x0141, 38, 35, 0},
+ {0x0111, 39, 36, 0},
+ {0x0085, 40, 37, 0},
+ {0x0049, 41, 38, 0},
+ {0x0025, 42, 39, 0},
+ {0x0015, 43, 40, 0},
+ {0x0009, 44, 41, 0},
+ {0x0005, 45, 42, 0},
+ {0x0001, 45, 43, 0},
+ {0x5601, 46, 46, 0}
+};
+
+typedef struct {
+ unsigned int state;
+ unsigned int mps;
+} J2kAecContext;
+
+typedef struct {
+ uint8_t *bp, *bpstart;
+ unsigned int a;
+ unsigned int c;
+ unsigned int ct;
+ J2kAecContext contexts[19];
+ J2kAecContext *curctx;
+} J2kAec;
+
+#define J2K_MAX_CBLKW 64
+#define J2K_MAX_CBLKH 64
+
+// T1 flags
+// flags determining significance of neighbour coefficients
+#define J2K_T1_SIG_N 0x0001
+#define J2K_T1_SIG_E 0x0002
+#define J2K_T1_SIG_W 0x0004
+#define J2K_T1_SIG_S 0x0008
+#define J2K_T1_SIG_NE 0x0010
+#define J2K_T1_SIG_NW 0x0020
+#define J2K_T1_SIG_SE 0x0040
+#define J2K_T1_SIG_SW 0x0080
+#define J2K_T1_SIG_NB (J2K_T1_SIG_N | J2K_T1_SIG_E | J2K_T1_SIG_S | J2K_T1_SIG_W \
+ |J2K_T1_SIG_NE | J2K_T1_SIG_NW | J2K_T1_SIG_SE | J2K_T1_SIG_SW)
+// flags determining sign bit of neighbour coefficients
+#define J2K_T1_SGN_N 0x0100
+#define J2K_T1_SGN_S 0x0200
+#define J2K_T1_SGN_W 0x0400
+#define J2K_T1_SGN_E 0x0800
+
+#define J2K_T1_VIS 0x1000
+#define J2K_T1_SIG 0x2000
+#define J2K_T1_REF 0x4000
+
+#define J2K_T1_CTX_RL 17
+#define J2K_T1_CTX_UNI 18
+
+typedef struct {
+ int data[J2K_MAX_CBLKW][J2K_MAX_CBLKH];
+ int flags[J2K_MAX_CBLKW+2][J2K_MAX_CBLKH+2];
+ J2kAec aec;
+} J2kT1Context;
+
+#endif
Added: jpeg2000/j2kenc.c
==============================================================================
--- (empty file)
+++ jpeg2000/j2kenc.c Mon Jun 25 12:28:41 2007
@@ -0,0 +1,1266 @@
+/*
+ * JPEG2000 image encoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ *
+ */
+
+/**
+ * JPEG2000 image encoder
+ * @file j2kenc.c
+ * @author Kamil Nowosad
+ */
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "j2k.h"
+#include "common.h"
+
+// TODO: doxygen-compatible comments
+
+typedef struct {
+ int length;
+ int npassess;
+ int zerobits;
+ int zero;
+ uint8_t data[8192];
+} J2kCblk; // code block
+
+typedef struct J2kTgtNode {
+ uint8_t val;
+ uint8_t vis;
+ struct J2kTgtNode *parent;
+} J2kTgtNode;
+
+typedef struct {
+ int xi0, xi1, yi0, yi1; /// indices of codeblocks ([xi0, xi1))
+} J2kPrec; // precinct
+
+typedef struct {
+ int x0, x1, y0, y1;
+ int cblkw, cblkh;
+ int cblknx, cblkny;
+ J2kPrec *prec;
+ J2kCblk *cblk;
+} J2kBand; // subband
+
+typedef struct {
+ int x0, x1, y0, y1;
+ int nbands;
+ int nprecw, nprech;
+ J2kBand *band;
+} J2kResLevel; // resolution level
+
+typedef struct {
+ J2kResLevel *reslevel;
+ int *data;
+ int x0, x1, y0, y1;
+} J2kComponent;
+
+typedef struct { // flatten with context
+ J2kComponent *comp;
+} J2kTile;
+
+typedef struct {
+ AVCodecContext *avctx;
+ AVFrame *picture;
+
+ int Xsiz, Ysiz; // image width and height
+ unsigned int bpp;
+ int ncomponents;
+ int ppx, ppy; // exponent of the precinct size [global]
+ int xcb, ycb; // exponent of the code block size
+ int XTsiz, YTsiz; // tile size
+ int numXtiles, numYtiles;
+
+ int expn;
+ int nguardbits;
+
+// int *samples[3];
+ int nreslevels; // number of resolution levels
+ uint8_t *buf_start;
+ uint8_t *buf;
+ uint8_t *buf_end;
+ int bit_index;
+
+ J2kTile *tile;
+} J2kEncoderContext;
+
+
+/* debug */
+#if 0
+#undef ifprintf
+#undef printf
+
+static void nspaces(FILE *fd, int n)
+{
+ while(n--) putc(' ', fd);
+}
+
+static void printv(int *tab, int l)
+{
+ int i;
+ for (i = 0; i < l; i++)
+ printf("%.3d ", tab[i]);
+ printf("\n");
+}
+
+static void printu(uint8_t *tab, int l)
+{
+ int i;
+ for (i = 0; i < l; i++)
+ printf("%.3hd ", tab[i]);
+ printf("\n");
+}
+
+static void printcomp(J2kComponent *comp)
+{
+ int i;
+ for (i = 0; i < comp->y1 - comp->y0; i++)
+ printv(comp->data + i * (comp->x1 - comp->x0), comp->x1 - comp->x0);
+}
+
+static void dump(J2kEncoderContext *s, FILE *fd)
+{
+ int tileno, compno, reslevelno, bandno, precno;
+ fprintf(fd, "XSiz = %d, YSiz = %d, XTsiz = %d, YTsiz = %d\n"
+ "numXtiles = %d, numYtiles = %d, ncomponents = %d\n"
+ "tiles:\n",
+ s->Xsiz, s->Ysiz, s->XTsiz, s->YTsiz,
+ s->numXtiles, s->numYtiles, s->ncomponents);
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ J2kTile *tile = s->tile + tileno;
+ nspaces(fd, 2);
+ fprintf(fd, "tile %d:\n", tileno);
+ for(compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ nspaces(fd, 4);
+ fprintf(fd, "component %d:\n", compno);
+ nspaces(fd, 4);
+ fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d\n",
+ comp->x0, comp->x1, comp->y0, comp->y1);
+ for(reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+ nspaces(fd, 6);
+ fprintf(fd, "reslevel %d:\n", reslevelno);
+ nspaces(fd, 6);
+ fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d, nbands = %d\n",
+ reslevel->x0, reslevel->x1, reslevel->y0,
+ reslevel->y1, reslevel->nbands);
+ for(bandno = 0; bandno < reslevel->nbands; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ nspaces(fd, 8);
+ fprintf(fd, "band %d:\n", bandno);
+ nspaces(fd, 8);
+ fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d,"
+ "cblkw = %d, cblkh = %d cblknx = %d cblkny = %d\n",
+ band->x0, band->x1,
+ band->y0, band->y1,
+ band->cblkw, band->cblkh,
+ band->cblknx, band->cblkny);
+ for (precno = 0; precno < reslevel->nprecw * reslevel->nprech; precno++){
+ J2kPrec *prec = band->prec + precno;
+ nspaces(fd, 10);
+ fprintf(fd, "prec %d:\n", precno);
+ nspaces(fd, 10);
+ fprintf(fd, "xi0 = %d, xi1 = %d, yi0 = %d, yi1 = %d\n",
+ prec->xi0, prec->xi1, prec->yi0, prec->yi1);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+/* misc tools */
+static int ceildivpow2(int a, int b)
+{
+ return (a + (1 << b) - 1)>> b;
+}
+
+static int ceildiv(int a, int b)
+{
+ return (a + b - 1) / b;
+}
+
+/* bitstream routines */
+
+/* put n times val bit */
+static void put_bits(J2kEncoderContext *s, int val, int n) // TODO: optimize
+{
+ while (n-- > 0){
+ if (s->bit_index == 8)
+ {
+ s->bit_index = *s->buf == 0xff ? 1:0;
+ *(++s->buf) = 0;
+ }
+ *s->buf |= val << (7 - s->bit_index++);
+ }
+}
+
+/* put n least significant bits of a number num */
+static void put_num(J2kEncoderContext *s, int num, int n)
+{
+ while(--n >= 0)
+ put_bits(s, (num & (1<<n)) ? 1:0, 1);
+}
+
+/* flush the bitstream */
+static void j2k_flush(J2kEncoderContext *s)
+{
+ if (s->bit_index){
+ s->bit_index = 0;
+ s->buf++;
+ }
+}
+
+/* tag tree routines */
+
+/* allocate the memory for tag tree */
+//TODO: optimize (too many mallocs)
+static J2kTgtNode *tag_tree_alloc(int w, int h)
+{
+ int i;
+ J2kTgtNode *t = av_malloc(w*h*sizeof(J2kTgtNode));
+ if (t == NULL)
+ return NULL;
+ for (i = 0; i < w*h; i++){
+ t[i].val = 0xff;
+ t[i].vis = 0;
+ }
+ return t;
+}
+
+static J2kTgtNode *tag_tree_init(int w, int h)
+{
+ J2kTgtNode *res = tag_tree_alloc(w, h),
+ *t = res;
+
+ if (res == NULL)
+ return NULL;
+
+ while (w > 1 || h > 1){
+ int pw = w, ph = h;
+ int i, j;
+ J2kTgtNode *t2;
+
+ w = (w+1) >> 1;
+ h = (h+1) >> 1;
+ t2 = tag_tree_alloc(w, h);
+ if (t2 == NULL)
+ return NULL;
+
+ for (i = 0; i < ph; i++)
+ for (j = 0; j < pw; j++){
+ t[i*pw + j].parent = &t2[(i>>1)*w + (j>>1)];
+ }
+ t = t2;
+ }
+ t[0].parent = NULL;
+ return res;
+}
+
+/* code the value stored in node */
+static void tag_tree_code(J2kEncoderContext *s, J2kTgtNode *node)
+{
+ J2kTgtNode *stack[30];
+ int sp = 1, curval = 0;
+ stack[0] = node;
+
+ node = node->parent;
+ while(node != NULL){
+ if (node->vis){
+ curval = node->val;
+ break;
+ }
+ node->vis++;
+ stack[sp++] = node;
+ node = node->parent;
+ }
+ while(--sp >= 0){
+ put_bits(s, 0, stack[sp]->val - curval);
+ put_bits(s, 1, 1);
+ curval = stack[sp]->val;
+ }
+}
+
+/* update the value in node */
+static void tag_tree_update(J2kTgtNode *node)
+{
+ int lev = 0;
+ while (node->parent != NULL){
+ if (node->parent->val <= node->val)
+ break;
+ node->parent->val = node->val;
+ node = node->parent;
+ lev++;
+ }
+}
+
+static void tag_tree_destroy(J2kTgtNode *tree)
+{
+ while (tree != NULL){
+ J2kTgtNode *parent = tree[0].parent;
+ av_free(tree);
+ tree = parent;
+ }
+}
+
+/* marker segments */
+static void put_marker(J2kEncoderContext *s, uint16_t marker)
+{
+ bytestream_put_be16(&s->buf, marker);
+}
+
+static void put_soc(J2kEncoderContext *s)
+{
+ put_marker(s, J2K_SOC);
+}
+
+static void put_siz(J2kEncoderContext *s)
+{
+ int i;
+
+ put_marker(s, J2K_SIZ);
+ bytestream_put_be16(&s->buf, 38 + 3 * s->ncomponents); // Lsiz
+ bytestream_put_be16(&s->buf, 0); // Rsiz
+ bytestream_put_be32(&s->buf, s->Xsiz); // Xsiz
+ bytestream_put_be32(&s->buf, s->Ysiz); // Ysiz
+ bytestream_put_be32(&s->buf, 0); // X0Siz
+ bytestream_put_be32(&s->buf, 0); // Y0Siz
+
+ bytestream_put_be32(&s->buf, s->XTsiz); // XTSiz
+ bytestream_put_be32(&s->buf, s->YTsiz); // YTSiz
+ bytestream_put_be32(&s->buf, 0); // XT0Siz
+ bytestream_put_be32(&s->buf, 0); // YT0Siz
+ bytestream_put_be16(&s->buf, s->ncomponents); // CSiz
+
+ for (i = 0; i < 3; i++){ // Ssiz_i XRsiz_i, YRsiz_i
+ bytestream_put_byte(&s->buf, 7);
+ bytestream_put_byte(&s->buf, 1);
+ bytestream_put_byte(&s->buf, 1);
+ }
+}
+
+static void put_cod(J2kEncoderContext *s)
+{
+ put_marker(s, J2K_COD);
+ bytestream_put_be16(&s->buf, 12); // Lcod
+ bytestream_put_byte(&s->buf, 0); // Scod
+ // SGcod
+ bytestream_put_byte(&s->buf, 0); // progression level
+ bytestream_put_be16(&s->buf, 1); // num of layers
+ bytestream_put_byte(&s->buf, 0); // multiple component transformation
+ // SPcod
+ bytestream_put_byte(&s->buf, s->nreslevels - 1); // num of decomp. levels
+ bytestream_put_byte(&s->buf, s->xcb-2); // cblk width
+ bytestream_put_byte(&s->buf, s->ycb-2); // cblk height
+ bytestream_put_byte(&s->buf, 0); // cblk style
+ bytestream_put_byte(&s->buf, 1); // transformation
+}
+
+static void put_qcd(J2kEncoderContext *s)
+{
+ int reslevelno;
+ put_marker(s, J2K_QCD);
+ bytestream_put_be16(&s->buf, 4+3*(s->nreslevels-1)); // LQcd
+ bytestream_put_byte(&s->buf, s->nguardbits << 5); // Sqcd
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ int bandno, nbands = reslevelno == 0 ? 1:3;
+ for (bandno = 0; bandno < nbands; bandno++)
+ bytestream_put_byte(&s->buf, s->expn << 3);
+ }
+}
+
+static uint8_t *put_sot(J2kEncoderContext *s, int tileno)
+{
+ uint8_t *psotptr;
+ put_marker(s, J2K_SOT);
+ bytestream_put_be16(&s->buf, 10); // Lsot
+ bytestream_put_be16(&s->buf, tileno); // Isot
+
+ psotptr = s->buf;
+ bytestream_put_be32(&s->buf, 0); // Psot (filled in later)
+
+ bytestream_put_byte(&s->buf, 0); // TPsot
+ bytestream_put_byte(&s->buf, 1); // TNsot
+ return psotptr;
+}
+
+/* compute the sizes of tiles, resolution levels, bands, etc.
+ * allocate memory for them
+ * divide the input image into tile-components
+ */
+static int init_tiles(J2kEncoderContext *s)
+{
+ // only one tile
+ // only rgb24 supported now
+ int y, x, tno, i;
+
+ s->numXtiles = ceildiv(s->Xsiz, s->XTsiz);
+ s->numYtiles = ceildiv(s->Ysiz, s->YTsiz);
+
+ s->tile = av_malloc(s->numXtiles * s->numYtiles * sizeof(J2kTile));
+ if (s->tile == NULL)
+ return -1;
+ for (tno = 0; tno < s->numXtiles * s->numYtiles; tno++){
+ J2kTile *tile = s->tile + tno;
+ int p = tno % s->numXtiles;
+ int q = tno / s->numXtiles;
+ int compno;
+
+ tile->comp = av_malloc(s->ncomponents * sizeof(J2kComponent));
+ if (tile->comp == NULL)
+ return -1;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ int reslevelno;
+
+ comp->x0 = p * s->XTsiz;
+ comp->x1 = FFMIN((p+1)*s->XTsiz, s->Xsiz);
+ comp->y0 = q * s->YTsiz;
+ comp->y1 = FFMIN((q+1)*s->YTsiz, s->Ysiz);
+
+ comp->data = av_malloc((comp->y1 - comp->y0) * (comp->x1 -comp->x0) * sizeof(int));
+ if (comp->data == NULL)
+ return -1;
+ comp->reslevel = av_malloc(s->nreslevels * sizeof(J2kResLevel));
+ if (comp->reslevel == NULL)
+ return -1;
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ int bandno;
+ int n = s->nreslevels - reslevelno;
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ reslevel->x0 = ceildivpow2(comp->x0, s->nreslevels - reslevelno - 1);
+ reslevel->x1 = ceildivpow2(comp->x1, s->nreslevels - reslevelno - 1);
+ reslevel->y0 = ceildivpow2(comp->y0, s->nreslevels - reslevelno - 1);
+ reslevel->y1 = ceildivpow2(comp->y1, s->nreslevels - reslevelno - 1);
+
+ if (reslevelno == 0)
+ reslevel->nbands = 1;
+ else
+ reslevel->nbands = 3;
+
+ if (reslevel->x1 == reslevel->x0)
+ reslevel->nprecw = 0;
+ else
+ reslevel->nprecw = ceildivpow2(reslevel->x1, s->ppx) - reslevel->x0 / (1<<s->ppx);
+
+ if (reslevel->y1 == reslevel->y0)
+ reslevel->nprech = 0;
+ else
+ reslevel->nprech = ceildivpow2(reslevel->y1, s->ppy) - reslevel->y0 / (1<<s->ppy);
+
+ reslevel->band = av_malloc(reslevel->nbands * sizeof(J2kBand));
+ if (reslevel->band == NULL)
+ return -1;
+ for (bandno = 0; bandno < reslevel->nbands; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ int cblkno, precx, precy, precno;
+ int x0, y0, x1, y1;
+ int xi0, yi0, xi1, yi1;
+ int cblkperprecw, cblkperprech;
+
+ if (reslevelno == 0){ // the same everywhere
+ band->cblkw = 1 << FFMIN(s->xcb, s->ppx-1);
+ band->cblkh = 1 << FFMIN(s->ycb, s->ppy-1);
+
+ band->x0 = ceildivpow2(comp->x0, n-1);
+ band->x1 = ceildivpow2(comp->x1, n-1);
+ band->y0 = ceildivpow2(comp->y0, n-1);
+ band->y1 = ceildivpow2(comp->y1, n-1);
+ }
+ else{
+ band->cblkw = 1 << FFMIN(s->xcb, s->ppx);
+ band->cblkh = 1 << FFMIN(s->ycb, s->ppy);
+
+ band->x0 = ceildivpow2(comp->x0 - (1 << (n-1)) * ((bandno+1)&1), n);
+ band->x1 = ceildivpow2(comp->x1 - (1 << (n-1)) * ((bandno+1)&1), n);
+ band->y0 = ceildivpow2(comp->y0 - (1 << (n-1)) * (((bandno+1)&2)>>1), n);
+ band->y1 = ceildivpow2(comp->y1 - (1 << (n-1)) * (((bandno+1)&2)>>1), n);
+ }
+
+ band->cblknx = ceildiv(band->x1 - band->x0, band->cblkw);
+ band->cblkny = ceildiv(band->y1 - band->y0, band->cblkh);
+
+ band->cblk = av_malloc(band->cblknx * band->cblkny * sizeof(J2kCblk));
+ if (band->cblk == NULL)
+ return -1;
+ band->prec = av_malloc(reslevel->nprecw * reslevel->nprech * sizeof(J2kPrec));
+ if (band->prec == NULL)
+ return -1;
+
+ for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+ band->cblk[cblkno].zero = 0;
+ }
+
+ y0 = band->y0;
+ y1 = (band->y0 + (1<<s->ppy))/(1<<s->ppy)*(1<<s->ppy) - band->y0;
+ yi0 = 0;
+ yi1 = ceildiv(y1 - y0, 1<<s->ycb) * (1<<s->ycb);
+ yi1 = FFMIN(yi1, band->cblkny);
+ cblkperprech = 1<<(s->ppy - s->ycb);
+ for (precy = 0, precno = 0; precy < reslevel->nprech; precy++){
+ for (precx = 0; precx < reslevel->nprecw; precx++, precno++){
+ band->prec[precno].yi0 = yi0;
+ band->prec[precno].yi1 = yi1;
+ }
+ yi1 += cblkperprech;
+ yi0 = yi1 - cblkperprech;
+ yi1 = FFMIN(yi1, band->cblkny);
+ }
+ x0 = band->x0;
+ x1 = (band->x0 + (1<<s->ppx))/(1<<s->ppx)*(1<<s->ppx) - band->x0;
+ xi0 = 0;
+ xi1 = ceildiv(x1 - x0, 1<<s->xcb) * (1<<s->xcb);
+ xi1 = FFMIN(xi1, band->cblknx);
+ cblkperprecw = 1<<(s->ppx - s->xcb);
+ for (precx = 0, precno = 0; precx < reslevel->nprecw; precx++){
+ for (precy = 0; precy < reslevel->nprech; precy++, precno = 0){
+ band->prec[precno].xi0 = xi0;
+ band->prec[precno].xi1 = xi1;
+ }
+ xi1 += cblkperprecw;
+ xi0 = xi1 - cblkperprecw;
+ xi1 = FFMIN(xi1, band->cblknx);
+ }
+ }
+ }
+ }
+ }
+ for (tno = 0; tno < s->numXtiles * s->numYtiles; tno++){
+ J2kTile *tile = s->tile + tno;
+ uint8_t *line = s->picture->data[0] + tile->comp[0].y0 * s->picture->linesize[0] + tile->comp[0].x0 * s->ncomponents;
+
+ i = 0;
+ for (y = tile->comp[0].y0; y < tile->comp[0].y1; y++){
+ uint8_t *ptr = line;
+ for (x = tile->comp[0].x0; x < tile->comp[0].x1; x++, i++){
+ int compno;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ tile->comp[compno].data[i] = *ptr++ - (1 << 7);
+ }
+ }
+ line += s->picture->linesize[0];
+ }
+ }
+ return 0;
+}
+
+/* discrete wavelet transform routines */
+static void sd_1d(int *p, int i0, int i1, int ileft, int iright)
+{
+#define PSE (i0 + FFMIN((i-i0+2*(i1-i0-1))%(2*(i1-i0-1)), 2*(i1-i0-1)-(i-i0+2*(i1-i0-1))%(2*(i1-i0-1))))
+ int i;
+
+ for (i = i0 - ileft; i < i0; i++){
+ p[i] = p[PSE];
+ }
+ for (i = i1; i < i1+iright; i++){
+ p[i] = p[PSE];
+ }
+
+ for (i = (i0+1)/2 - 1; i < (i1+1)/2; i++){
+ p[2*i+1] -= (p[2*i] + p[2*i+2]) >> 1;
+ }
+ for (i = (i0+1)/2; i < (i1+1)/2; i++){
+ p[2*i] += (p[2*i-1] + p[2*i+1] + 2) >> 2;
+ }
+#undef PSE
+}
+
+static void dwt_encode53(J2kEncoderContext *s, J2kComponent *comp)
+{
+ int lev = s->nreslevels,
+ *t = comp->data, w = comp->x1 - comp->x0;
+ int *ppv = av_malloc((comp->reslevel[lev-1].y1 + 4)*sizeof(int)), *pv = ppv+2;
+ int *ppu = av_malloc((comp->reslevel[lev-1].x1 + 4)*sizeof(int)), *pu = ppu+2;
+
+ while (--lev){
+ int u0 = comp->reslevel[lev].x0,
+ u1 = comp->reslevel[lev].x1,
+ v0 = comp->reslevel[lev].y0,
+ v1 = comp->reslevel[lev].y1,
+ u = u0, v = v0;
+ const static int tileft[2] = {2, 1}, tiright[2] = {1, 2};
+
+ //VER_SD
+ while (u < u1){
+ int i, j;
+ for (i = v0; i < v1; i++)
+ pv[i] = t[w*(i-v0) + u-u0];
+ sd_1d(pv, v0, v1, tileft[v0&1], tiright[v1&1]);
+
+ // copy back and deinterleave
+ for (i = (v0+1)/2, j = 0; i < (v1+1)/2; i++, j++){
+ t[w*j + u-u0] = pv[2*i];
+ }
+ for (i = v0/2; i < v1/2; i++, j++){
+ t[w*j + u-u0] = pv[2*i+1];
+ }
+ u++;
+ }
+
+ //HOR_SD
+ while (v < v1){
+ int i, j;
+ for (i = u0; i < u1; i++)
+ pu[i] = t[w*(v-v0) + i-u0];
+ sd_1d(pu, u0, u1, tileft[u0&1], tiright[u1&1]);
+
+ // copy back and deinterleave
+ for (i = (u0+1)/2, j = 0; i < (u1+1)/2; i++, j++){
+ t[w*(v-v0) + j] = pu[2*i];
+ }
+ for (i = u0/2; i < u1/2; i++, j++){
+ t[w*(v-v0) + j] = pu[2*i + 1];
+ }
+ v++;
+ }
+ }
+ av_free(ppv);
+ av_free(ppu);
+}
+
+/* arithmetic entropy coder routines: */
+static void aec_initenc(J2kAec *aec, uint8_t *bp)
+{
+ bzero(aec->contexts, 19*sizeof(J2kAecContext));
+ aec->contexts[J2K_T1_CTX_UNI].state = 46;
+ aec->contexts[J2K_T1_CTX_RL].state = 3;
+ aec->contexts[0].state = 4;
+ aec->curctx = aec->contexts;
+
+ aec->a = 0x8000;
+ aec->c = 0;
+ aec->bp = bp-1;
+ aec->bpstart = bp;
+ if (*aec->bp == 0xff)
+ aec->ct = 13;
+ else
+ aec->ct = 12;
+}
+
+static void aec_byteout_l(J2kAec *aec)
+{
+ aec->bp++;
+ *aec->bp = aec->c >> 19;
+ aec->c &= 0x7ffff;
+ aec->ct = 8;
+}
+
+static void aec_byteout_r(J2kAec *aec)
+{
+ aec->bp++;
+ *aec->bp = aec->c >> 20;
+ aec->c &= 0xfffff;
+ aec->ct = 7;
+}
+
+static void aec_byteout(J2kAec *aec)
+{
+ if (*aec->bp == 0xff){
+ aec_byteout_r(aec);
+ }
+ else
+ {
+ if ((aec->c & 0x8000000) == 0){
+ aec_byteout_l(aec);
+ }
+ else{
+ (*aec->bp)++;
+ if (*aec->bp == 0xff){
+ aec->c &= 0x7ffffff;
+ aec_byteout_r(aec);
+ }
+ else{
+ aec_byteout_l(aec);
+ }
+ }
+ }
+}
+
+static void aec_renorme(J2kAec *aec)
+{
+ do{
+ aec->a = aec->a << 1;
+ aec->c = aec->c << 1;
+ aec->ct--;
+ if (!aec->ct)
+ aec_byteout(aec);
+ }
+ while ((aec->a & 0x8000) == 0);
+}
+
+static void aec_codelps(J2kAec *aec)
+{
+ int qe = aec_cx_states[aec->curctx->state].qe;
+ aec->a -= qe;
+ if (aec->a < qe)
+ aec->c += qe;
+ else
+ aec->a = qe;
+ if (aec_cx_states[aec->curctx->state].sw)
+ aec->curctx->mps = 1 - aec->curctx->mps;
+ aec->curctx->state = aec_cx_states[aec->curctx->state].nlps;
+ aec_renorme(aec);
+}
+
+static void aec_codemps(J2kAec *aec)
+{
+ int qe = aec_cx_states[aec->curctx->state].qe;
+ aec->a -= qe;
+ if ((aec->a & 0x8000) == 0){
+ if (aec->a < qe)
+ aec->a = qe;
+ else
+ aec->c += qe;
+ aec->curctx->state = aec_cx_states[aec->curctx->state].nmps;
+ aec_renorme(aec);
+ }
+ else
+ aec->c += qe;
+}
+
+/* code bit d with context cx */
+static void aec_encode(J2kAec *aec, int cx, int d)
+{
+ aec->curctx = aec->contexts + cx;
+ if (aec->curctx->mps == d){
+ aec_codemps(aec);
+ }
+ else{
+ aec_codelps(aec);
+ }
+}
+
+static void aec_setbits(J2kAec *aec)
+{
+ int tmp = aec->c + aec->a;
+ aec->c |= 0xffff;
+ if (aec->c >= tmp)
+ aec->c -= 0x8000;
+}
+
+/* flush the encoder [returns number of bytes encoded] */
+static int aec_flush(J2kAec *aec)
+{
+ aec_setbits(aec);
+ aec->c = aec->c << aec->ct;
+ aec_byteout(aec);
+ aec->c = aec->c << aec->ct;
+ aec_byteout(aec);
+ if (*aec->bp != 0xff)
+ aec->bp++;
+ return aec->bp - aec->bpstart;
+}
+
+/* tier-1 routines */
+static int getnbctxno(int flag, int bandno)
+{
+ int h, v, d;
+
+ h = ((flag & J2K_T1_SIG_E) ? 1:0)+
+ ((flag & J2K_T1_SIG_W) ? 1:0);
+ v = ((flag & J2K_T1_SIG_N) ? 1:0)+
+ ((flag & J2K_T1_SIG_S) ? 1:0);
+ d = ((flag & J2K_T1_SIG_NE) ? 1:0)+
+ ((flag & J2K_T1_SIG_NW) ? 1:0)+
+ ((flag & J2K_T1_SIG_SE) ? 1:0)+
+ ((flag & J2K_T1_SIG_SW) ? 1:0);
+ switch(bandno){
+ case 0: // LL || LH
+ case 2:
+ if (h == 2) return 8;
+ if (h == 1){
+ if (v >= 1) return 7;
+ if (d >= 1) return 6;
+ return 5;
+ }
+ if (v == 2) return 4;
+ if (v == 1) return 3;
+ if (d >= 2) return 2;
+ if (d == 1) return 1;
+ return 0;
+ case 1: // HL
+ if (v == 2) return 8;
+ if (v == 1){
+ if (h >= 1) return 7;
+ if (d >= 1) return 6;
+ return 5;
+ }
+ if (h == 2) return 4;
+ if (h == 1) return 3;
+ if (d >= 2) return 2;
+ if (d >= 1) return 1;
+ return 0;
+ case 3:
+ if (d >= 3) return 8;
+ if (d == 2){
+ if (h+v >= 1) return 7;
+ return 6;
+ }
+ if (d == 1){
+ if (h+v >= 2) return 5;
+ if (h+v == 1) return 4;
+ return 3;
+ }
+ if (h+v >= 2) return 2;
+ if (h+v == 1) return 1;
+ return 0;
+ }
+ assert(0);
+}
+
+static int getrefctxno(int flag)
+{
+ if (!(flag & J2K_T1_REF)){
+ if (flag & J2K_T1_SIG_NB)
+ return 15;
+ return 14;
+ }
+ return 16;
+}
+
+static int getsgnctxno(int flag, int *xorbit)
+{
+ int vcontrib, hcontrib;
+ const int contribtab[3][3] = {{0, -1, 1}, {-1, -1, 0}, {1, 0, 1}};
+ const int ctxlbltab[3][3] = {{13, 12, 11}, {10, 9, 10}, {11, 12, 13}};
+ const int xorbittab[3][3] = {{1, 1, 1,}, {1, 0, 0}, {0, 0, 0}};
+
+ hcontrib = contribtab[flag & J2K_T1_SIG_E ? flag & J2K_T1_SGN_E ? 1:2:0]
+ [flag & J2K_T1_SIG_W ? flag & J2K_T1_SGN_W ? 1:2:0]+1;
+ vcontrib = contribtab[flag & J2K_T1_SIG_S ? flag & J2K_T1_SGN_S ? 1:2:0]
+ [flag & J2K_T1_SIG_N ? flag & J2K_T1_SGN_N ? 1:2:0]+1;
+ *xorbit = xorbittab[hcontrib][vcontrib];
+ return ctxlbltab[hcontrib][vcontrib];
+}
+
+static void set_significant(J2kT1Context *t1, int x, int y)
+{
+ x++; y++;
+ t1->flags[y][x] |= J2K_T1_SIG;
+ if (t1->data[y-1][x-1] < 0){
+ t1->flags[y][x+1] |= J2K_T1_SIG_W | J2K_T1_SGN_W;
+ t1->flags[y][x-1] |= J2K_T1_SIG_E | J2K_T1_SGN_E;
+ t1->flags[y+1][x] |= J2K_T1_SIG_N | J2K_T1_SGN_N;
+ t1->flags[y-1][x] |= J2K_T1_SIG_S | J2K_T1_SGN_S;
+ }
+ else{
+ t1->flags[y][x+1] |= J2K_T1_SIG_W;
+ t1->flags[y][x-1] |= J2K_T1_SIG_E;
+ t1->flags[y+1][x] |= J2K_T1_SIG_N;
+ t1->flags[y-1][x] |= J2K_T1_SIG_S;
+ }
+ t1->flags[y+1][x+1] |= J2K_T1_SIG_NW;
+ t1->flags[y+1][x-1] |= J2K_T1_SIG_NE;
+ t1->flags[y-1][x+1] |= J2K_T1_SIG_SW;
+ t1->flags[y-1][x-1] |= J2K_T1_SIG_SE;
+}
+
+
+static void encode_sigpass(J2kT1Context *t1, int width, int height, int mask, int bandno)
+{
+ int i, j, k;
+ for (i = 0; i < height; i += 4)
+ for (j = 0; j < width; j++)
+ for (k = i; k < height && k < i+4; k++){
+ if (!(t1->flags[k+1][j+1] & J2K_T1_SIG) && (t1->flags[k+1][j+1] & J2K_T1_SIG_NB)){
+ int ctxno = getnbctxno(t1->flags[k+1][j+1], bandno),
+ bit = abs(t1->data[k][j]) & mask ? 1 : 0;
+ aec_encode(&t1->aec, ctxno, bit);
+ if (bit){
+ int xorbit;
+ int ctxno = getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+ aec_encode(&t1->aec, ctxno, (t1->data[k][j] < 0 ? 1:0) ^ xorbit);
+ set_significant(t1, j, k);
+ }
+ t1->flags[k+1][j+1] |= J2K_T1_VIS;
+ }
+ }
+}
+
+static void encode_refpass(J2kT1Context *t1, int width, int height, int mask)
+{
+ int i, j, k;
+ for (i = 0; i < height; i += 4)
+ for (j = 0; j < width; j++)
+ for (k = i; k < height && k < i+4; k++)
+ if ((t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS)) == J2K_T1_SIG){
+ int ctxno = getrefctxno(t1->flags[k+1][j+1]);
+ aec_encode(&t1->aec, ctxno, abs(t1->data[k][j]) & mask ? 1:0);
+ t1->flags[k+1][j+1] |= J2K_T1_REF;
+ }
+}
+
+static void encode_clnpass(J2kT1Context *t1, int width, int height, int mask, int bandno)
+{
+ int i, j, k;
+ for (i = 0; i < height; i += 4)
+ for (j = 0; j < width; j++){
+ if (i + 3 < height && !(
+ (t1->flags[i+1][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[i+2][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[i+3][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[i+4][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG))))
+ {
+ // aggregation mode
+ int rlen;
+ for (rlen = 0; rlen < 4; rlen++)
+ if (abs(t1->data[i+rlen][j]) & mask)
+ break;
+ aec_encode(&t1->aec, J2K_T1_CTX_RL, rlen != 4);
+ if (rlen == 4)
+ continue;
+ aec_encode(&t1->aec, J2K_T1_CTX_UNI, rlen >> 1);
+ aec_encode(&t1->aec, J2K_T1_CTX_UNI, rlen & 1);
+ for (k = i + rlen; k < i + 4; k++){
+ if (!(t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+ int ctxno = getnbctxno(t1->flags[k+1][j+1], bandno);
+ if (k > i + rlen)
+ aec_encode(&t1->aec, ctxno, abs(t1->data[k][j]) & mask ? 1:0);
+ if (abs(t1->data[k][j]) & mask){ // newly significant
+ int xorbit;
+ int ctxno = getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+ aec_encode(&t1->aec, ctxno, (t1->data[k][j] < 0 ? 1:0) ^ xorbit);
+ set_significant(t1, j, k);
+ }
+ }
+ t1->flags[k+1][j+1] &= ~J2K_T1_VIS;
+ }
+ }
+ else{
+ for (k = i; k < i + 4 && k < height; k++){
+ if (!(t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+ int ctxno = getnbctxno(t1->flags[k+1][j+1], bandno);
+ aec_encode(&t1->aec, ctxno, abs(t1->data[k][j]) & mask ? 1:0);
+ if (abs(t1->data[k][j]) & mask){ // newly significant
+ int xorbit;
+ int ctxno = getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+ aec_encode(&t1->aec, ctxno, (t1->data[k][j] < 0 ? 1:0) ^ xorbit);
+ set_significant(t1, j, k);
+ }
+ }
+ t1->flags[k+1][j+1] &= ~J2K_T1_VIS;
+ }
+ }
+ }
+}
+
+static void encode_cblk(J2kEncoderContext *s, J2kT1Context *t1, J2kCblk *cblk, int width, int height, int bandno)
+{
+ int pass_t = 2, passno, i, j, mask, max=0, nonzerobits;
+
+ for (i = 0; i < height+2; i++)
+ bzero(t1->flags[i], (width+2)*sizeof(int));
+
+ for (i = 0; i < height; i++){
+ for (j = 0; j < width; j++)
+ max = FFMAX(max, abs(t1->data[i][j]));
+ }
+
+ if (max == 0){
+ // XXX: both should be 0, but something goes wrong, when set so
+ // - to be corrected
+ nonzerobits = 1;
+ mask = 1;
+ }
+ else{
+ nonzerobits = av_log2(max) + 1;
+ mask = 1 << (nonzerobits - 1);
+ }
+
+ aec_initenc(&t1->aec, cblk->data);
+
+ cblk->zerobits = s->expn + s->nguardbits - 1 - nonzerobits;
+
+ for (passno = 0; mask != 0; passno++){
+ switch(pass_t){
+ case 0: encode_sigpass(t1, width, height, mask, bandno);
+ break;
+ case 1: encode_refpass(t1, width, height, mask);
+ break;
+ case 2: encode_clnpass(t1, width, height, mask, bandno);
+ break;
+ }
+ if (++pass_t == 3){
+ pass_t = 0;
+ mask = mask >> 1;
+ }
+ }
+ cblk->npassess = passno;
+
+ // TODO: optional flush on each pass
+ cblk->length = aec_flush(&t1->aec);
+}
+
+/* tier-2 routines: */
+
+static void putnumpassess(J2kEncoderContext *s, int n)
+{
+ if (n == 1)
+ put_num(s, 0, 1);
+ else if (n == 2)
+ put_num(s, 2, 2);
+ else if (n <= 5)
+ put_num(s, 0xc | (n-3), 4);
+ else if (n <= 36)
+ put_num(s, 0x1e0 | (n-6), 9);
+ else
+ put_num(s, 0xff80 | (n-37), 16);
+}
+
+
+static void encode_packet(J2kEncoderContext *s, J2kResLevel *rlevel, int precno)
+{
+ int bandno;
+
+ // init bitstream
+ *s->buf = 0;
+ s->bit_index = 0;
+
+ // header
+
+ // is the packet empty?
+ put_bits(s, 1, 1); // 1 - there are not any empty packets
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ J2kTgtNode *cblkincl, *zerobits;
+ int cblknw, cblknh, yi, xi, pos;
+
+ cblknh = band->prec[precno].yi1 - band->prec[precno].yi0;
+ cblknw = band->prec[precno].xi1 - band->prec[precno].xi0;
+
+ cblkincl = tag_tree_init(cblknw, cblknh);
+ zerobits = tag_tree_init(cblknw, cblknh);
+
+ for (pos=0, yi = band->prec[precno].yi0; yi < band->prec[precno].yi1; yi++){
+ for (xi = band->prec[precno].xi0; xi < band->prec[precno].xi1; xi++, pos++){
+ cblkincl[pos].val = 0;
+ tag_tree_update(cblkincl + pos);
+ zerobits[pos].val = band->cblk[yi * cblknw + xi].zerobits;
+ tag_tree_update(zerobits + pos);
+ }
+ }
+
+ for (pos=0, yi = band->prec[precno].yi0; yi < band->prec[precno].yi1; yi++){
+ for (xi = band->prec[precno].xi0; xi < band->prec[precno].xi1; xi++, pos++){
+ int pad = 0, llen;
+ J2kCblk *cblk = band->cblk + yi * cblknw + xi;
+
+ // inclusion information
+ tag_tree_code(s, cblkincl + pos);
+ // zerobits information
+ tag_tree_code(s, zerobits + pos);
+ // number of passess
+ putnumpassess(s, cblk->npassess);
+
+ llen = av_log2(cblk->length) - av_log2(cblk->npassess) - 2;
+ if (llen < 0){
+ pad = -llen;
+ llen = 0;
+ }
+ // length of code block
+ put_bits(s, 1, llen);
+ put_bits(s, 0, 1);
+ put_num(s, cblk->length, av_log2(cblk->length)+1+pad);
+ }
+ }
+
+ tag_tree_destroy(cblkincl);
+ tag_tree_destroy(zerobits);
+ }
+ j2k_flush(s);
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ int cblknw, yi;
+ cblknw = band->prec[precno].xi1 - band->prec[precno].xi0;
+ for (yi = band->prec[precno].yi0; yi < band->prec[precno].yi1; yi++){
+ int xi;
+ for (xi = band->prec[precno].xi0; xi < band->prec[precno].xi1; xi++){
+ J2kCblk *cblk = band->cblk + yi * cblknw + xi;
+ bytestream_put_buffer(&s->buf, cblk->data, cblk->length);
+ }
+ }
+ }
+}
+
+static void encode_tile(J2kEncoderContext *s, int tileno)
+{
+ int compno, reslevelno, bandno;
+ J2kT1Context t1;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = s->tile[tileno].comp + compno;
+
+ av_log(s->avctx, AV_LOG_DEBUG,"dwt\n");
+ dwt_encode53(s, &s->tile[tileno].comp[compno]);
+ av_log(s->avctx, AV_LOG_DEBUG,"after dwt -> tier1\n");
+
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ int cblkx, cblky, cblkno=0, xx0, x0, xx1, y0, yy0, yy1;
+ yy0 = bandno == 0 ? 0 : comp->reslevel[reslevelno-1].y1 - comp->reslevel[reslevelno-1].y0;
+ y0 = yy0;
+ yy1 = FFMIN(ceildiv(band->y0 + 1, band->cblkh) * band->cblkh, band->y1) - band->y0 + yy0;
+
+ for (cblky = 0; cblky < band->cblkny; cblky++){
+ if (reslevelno == 0 || bandno == 1)
+ xx0 = 0;
+ else
+ xx0 = comp->reslevel[reslevelno-1].x1 - comp->reslevel[reslevelno-1].x0;
+ x0 = xx0;
+ xx1 = FFMIN(ceildiv(band->x0 + 1, band->cblkw) * band->cblkw, band->x1) - band->x0 + xx0;
+
+ for (cblkx = 0; cblkx < band->cblknx; cblkx++, cblkno++){
+ int y, x;
+ for (y = yy0; y < yy1; y++){
+ int *ptr = t1.data[y-yy0];
+ for (x = xx0; x < xx1; x++)
+ *ptr++ = comp->data[(comp->x1 - comp->x0) * y + x];
+ }
+ encode_cblk(s, &t1, band->cblk + cblkno, xx1 - xx0, yy1 - yy0, bandno + (reslevelno > 0?1:0));
+ xx0 = xx1;
+ xx1 = FFMIN(xx1 + band->cblkw, band->x1 - band->x0 + x0);
+ }
+ yy0 = yy1;
+ yy1 = FFMIN(yy1 + band->cblkh, band->y1 - band->y0 + y0);
+ }
+ }
+ }
+ av_free(comp->data);
+ av_log(s->avctx, AV_LOG_DEBUG, "after tier1\n");
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "tier2\n");
+ // lay-rlevel-comp-pos progression
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ int precno;
+ J2kResLevel *reslevel = s->tile[tileno].comp[compno].reslevel + reslevelno;
+ for (precno = 0; precno < reslevel->nprecw * reslevel->nprech; precno++){
+ encode_packet(s, reslevel, precno);
+ }
+ }
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "after tier2\n");
+}
+
+void free(J2kEncoderContext *s)
+{
+ int tileno, compno, reslevelno, bandno;
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = s->tile[tileno].comp + compno;
+
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ av_free(band->cblk);
+ av_free(band->prec);
+ }
+ av_free(reslevel->band);
+ }
+ av_free(comp->reslevel);
+ }
+ av_free(s->tile[tileno].comp);
+ }
+ av_free(s->tile);
+}
+
+static int encode_frame(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size,
+ void *data)
+{
+ int tileno;
+ J2kEncoderContext *s = avctx->priv_data;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "start\n");
+ s->picture = data;
+
+ // defaults:
+ // TODO: implement setting non-standard precinct size
+ s->ppx = 15; s->ppy = 15;
+
+ s->XTsiz = 256; s->YTsiz = 256;
+ s->nreslevels = 7;
+ s->xcb = s->ycb = 4;
+
+ // init:
+ s->buf = s->buf_start = buf;
+ s->buf_end = buf + buf_size;
+ s->Xsiz = avctx->width;
+ s->Ysiz = avctx->height;
+
+
+ // TODO: other pixel formats
+ if (avctx->pix_fmt == PIX_FMT_RGB24){
+ s->ncomponents = 3;
+ s->bpp = 24;
+
+ // XXX: to beverified (after adding quantization)
+ // (now it just works, but i'm not sure why ;-) )
+ s->nguardbits = 1;
+ s->expn = 8;
+ }
+ else{
+ av_log(avctx, AV_LOG_ERROR, "only rgb24 supported\n");
+ }
+
+ put_soc(s);
+ put_siz(s);
+ put_cod(s);
+ put_qcd(s);
+
+ av_log(s->avctx, AV_LOG_DEBUG, "init\n");
+ init_tiles(s);
+ av_log(s->avctx, AV_LOG_DEBUG, "after init\n");
+
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ uint8_t *psotptr;
+ psotptr = put_sot(s, tileno);
+ put_marker(s, J2K_SOD);
+ encode_tile(s, tileno);
+ bytestream_put_be32(&psotptr, s->buf - psotptr + 6);
+ }
+ put_marker(s, J2K_EOC);
+
+ free(s);
+ av_log(s->avctx, AV_LOG_DEBUG, "end\n");
+ return s->buf - s->buf_start;
+}
+
+AVCodec jpeg2000_encoder = {
+ "j2k",
+ CODEC_TYPE_VIDEO,
+ CODEC_ID_JPEG2000,
+ sizeof(J2kEncoderContext),
+ NULL,
+ encode_frame,
+ NULL,
+ NULL,
+ 0,
+ .pix_fmts =
+ (enum PixelFormat[]) {PIX_FMT_RGB24, -1}
+};
7
8
[soc]: r287 - in jpeg2000: aec.h aecenc.c checkout.sh ffmpeg.patch j2k.h j2kenc.c
by k.nowosad 03 Jul '07
by k.nowosad 03 Jul '07
03 Jul '07
Author: k.nowosad
Date: Sat Jun 30 16:14:53 2007
New Revision: 287
Log:
moved the arithmetic coder into a separate file
Added:
jpeg2000/aec.h
jpeg2000/aecenc.c
Modified:
jpeg2000/checkout.sh
jpeg2000/ffmpeg.patch
jpeg2000/j2k.h
jpeg2000/j2kenc.c
Added: jpeg2000/aec.h
==============================================================================
--- (empty file)
+++ jpeg2000/aec.h Sat Jun 30 16:14:53 2007
@@ -0,0 +1,123 @@
+/*
+ * Arithmetic entropy coder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ *
+ */
+
+/**
+ * Arithmetic entropy coder
+ * @file aec.h
+ * @author Kamil Nowosad
+ */
+
+/* arithmetic entropy coder context */
+//TODO: optimize [nice solution in openjpeg]
+
+#ifndef AEC_H
+#define AEC_H
+
+#include "avcodec.h"
+
+#define AEC_CX_UNI 17
+#define AEC_CX_RL 18
+
+typedef struct {
+ unsigned int qe;
+ unsigned int nmps;
+ unsigned int nlps;
+ unsigned int sw;
+} AecCxState;
+
+const static AecCxState cx_states[47] = {
+ {0x5601, 1, 1, 1},
+ {0x3401, 2, 6, 0},
+ {0x1801, 3, 9, 0},
+ {0x0AC1, 4, 12, 0},
+ {0x0521, 5, 29, 0},
+ {0x0221, 38, 33, 0},
+ {0x5601, 7, 6, 1},
+ {0x5401, 8, 14, 0},
+ {0x4801, 9, 14, 0},
+ {0x3801, 10, 14, 0},
+ {0x3001, 11, 17, 0},
+ {0x2401, 12, 18, 0},
+ {0x1C01, 13, 20, 0},
+ {0x1601, 29, 21, 0},
+ {0x5601, 15, 14, 1},
+ {0x5401, 16, 14, 0},
+ {0x5101, 17, 15, 0},
+ {0x4801, 18, 16, 0},
+ {0x3801, 19, 17, 0},
+ {0x3401, 20, 18, 0},
+ {0x3001, 21, 19, 0},
+ {0x2801, 22, 19, 0},
+ {0x2401, 23, 20, 0},
+ {0x2201, 24, 21, 0},
+ {0x1C01, 25, 22, 0},
+ {0x1801, 26, 23, 0},
+ {0x1601, 27, 24, 0},
+ {0x1401, 28, 25, 0},
+ {0x1201, 29, 26, 0},
+ {0x1101, 30, 27, 0},
+ {0x0AC1, 31, 28, 0},
+ {0x09C1, 32, 29, 0},
+ {0x08A1, 33, 30, 0},
+ {0x0521, 34, 31, 0},
+ {0x0441, 35, 32, 0},
+ {0x02A1, 36, 33, 0},
+ {0x0221, 37, 34, 0},
+ {0x0141, 38, 35, 0},
+ {0x0111, 39, 36, 0},
+ {0x0085, 40, 37, 0},
+ {0x0049, 41, 38, 0},
+ {0x0025, 42, 39, 0},
+ {0x0015, 43, 40, 0},
+ {0x0009, 44, 41, 0},
+ {0x0005, 45, 42, 0},
+ {0x0001, 45, 43, 0},
+ {0x5601, 46, 46, 0}
+};
+
+typedef struct {
+ unsigned int state;
+ unsigned int mps;
+} AecContext;
+
+typedef struct {
+ uint8_t *bp, *bpstart;
+ unsigned int a;
+ unsigned int c;
+ unsigned int ct;
+ AecContext contexts[19];
+ AecContext *curctx;
+} AecState;
+
+void aec_initenc(AecState *aec, uint8_t *bp);
+
+/**
+ * code bit d with context cx
+ * */
+void aec_encode(AecState *aec, int cx, int d);
+
+/**
+ * flush the encoder [returns number of bytes encoded]
+ * */
+int aec_flush(AecState *aec);
+
+#endif
Added: jpeg2000/aecenc.c
==============================================================================
--- (empty file)
+++ jpeg2000/aecenc.c Sat Jun 30 16:14:53 2007
@@ -0,0 +1,159 @@
+/*
+ * Arithmetic entropy coder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ *
+ */
+
+/**
+ * Arithmetic entropy coder
+ * @file aecenc.c
+ * @author Kamil Nowosad
+ */
+
+#include "aec.h"
+
+static void byteout_l(AecState *aec)
+{
+ aec->bp++;
+ *aec->bp = aec->c >> 19;
+ aec->c &= 0x7ffff;
+ aec->ct = 8;
+}
+
+static void byteout_r(AecState *aec)
+{
+ aec->bp++;
+ *aec->bp = aec->c >> 20;
+ aec->c &= 0xfffff;
+ aec->ct = 7;
+}
+
+static void byteout(AecState *aec)
+{
+ if (*aec->bp == 0xff){
+ byteout_r(aec);
+ }
+ else
+ {
+ if ((aec->c & 0x8000000) == 0){
+ byteout_l(aec);
+ }
+ else{
+ (*aec->bp)++;
+ if (*aec->bp == 0xff){
+ aec->c &= 0x7ffffff;
+ byteout_r(aec);
+ }
+ else{
+ byteout_l(aec);
+ }
+ }
+ }
+}
+
+static void renorme(AecState *aec)
+{
+ do{
+ aec->a = aec->a << 1;
+ aec->c = aec->c << 1;
+ aec->ct--;
+ if (!aec->ct)
+ byteout(aec);
+ }
+ while ((aec->a & 0x8000) == 0);
+}
+
+static void codelps(AecState *aec)
+{
+ int qe = cx_states[aec->curctx->state].qe;
+ aec->a -= qe;
+ if (aec->a < qe)
+ aec->c += qe;
+ else
+ aec->a = qe;
+ if (cx_states[aec->curctx->state].sw)
+ aec->curctx->mps = 1 - aec->curctx->mps;
+ aec->curctx->state = cx_states[aec->curctx->state].nlps;
+ renorme(aec);
+}
+
+static void codemps(AecState *aec)
+{
+ int qe = cx_states[aec->curctx->state].qe;
+ aec->a -= qe;
+ if ((aec->a & 0x8000) == 0){
+ if (aec->a < qe)
+ aec->a = qe;
+ else
+ aec->c += qe;
+ aec->curctx->state = cx_states[aec->curctx->state].nmps;
+ renorme(aec);
+ }
+ else
+ aec->c += qe;
+}
+
+static void setbits(AecState *aec)
+{
+ int tmp = aec->c + aec->a;
+ aec->c |= 0xffff;
+ if (aec->c >= tmp)
+ aec->c -= 0x8000;
+}
+
+void aec_initenc(AecState *aec, uint8_t *bp)
+{
+ bzero(aec->contexts, 19*sizeof(AecContext));
+ aec->contexts[AEC_CX_UNI].state = 46;
+ aec->contexts[AEC_CX_RL].state = 3;
+ aec->contexts[0].state = 4;
+ aec->curctx = aec->contexts;
+
+ aec->a = 0x8000;
+ aec->c = 0;
+ aec->bp = bp-1;
+ aec->bpstart = bp;
+ if (*aec->bp == 0xff)
+ aec->ct = 13;
+ else
+ aec->ct = 12;
+}
+
+void aec_encode(AecState *aec, int cx, int d)
+{
+ aec->curctx = aec->contexts + cx;
+ if (aec->curctx->mps == d){
+ codemps(aec);
+ }
+ else{
+ codelps(aec);
+ }
+}
+
+int aec_flush(AecState *aec)
+{
+ setbits(aec);
+ aec->c = aec->c << aec->ct;
+ byteout(aec);
+ aec->c = aec->c << aec->ct;
+ byteout(aec);
+ if (*aec->bp != 0xff)
+ aec->bp++;
+ return aec->bp - aec->bpstart;
+}
Modified: jpeg2000/checkout.sh
==============================================================================
--- jpeg2000/checkout.sh (original)
+++ jpeg2000/checkout.sh Sat Jun 30 16:14:53 2007
@@ -6,4 +6,6 @@ patch -p0 <../../ffmpeg.patch
echo "copying the jpeg2000 files to ffmpeg/libavcodec"
ln -s ../../j2kenc.c j2kenc.c
ln -s ../../j2k.h j2k.h
+ln -s ../../aecenc.c aecenc.c
+ln -s ../../aec.h aec.h
echo "Done, now just do a regular configure and make to build."
Modified: jpeg2000/ffmpeg.patch
==============================================================================
--- jpeg2000/ffmpeg.patch (original)
+++ jpeg2000/ffmpeg.patch Sat Jun 30 16:14:53 2007
@@ -1,18 +1,18 @@
Index: Makefile
===================================================================
---- Makefile (wersja 9417)
+--- Makefile (wersja 9451)
+++ Makefile (kopia robocza)
@@ -93,6 +93,7 @@
OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o
OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o
OBJS-$(CONFIG_INTERPLAY_DPCM_DECODER) += dpcm.o
-+OBJS-$(CONFIG_JPEG2000_ENCODER) += j2kenc.o
++OBJS-$(CONFIG_JPEG2000_ENCODER) += j2kenc.o aecenc.o
OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o mjpegdec.o mjpeg.o golomb.o
OBJS-$(CONFIG_JPEGLS_ENCODER) += jpeglsenc.o jpegls.o golomb.o
OBJS-$(CONFIG_KMVC_DECODER) += kmvc.o
Index: allcodecs.c
===================================================================
---- allcodecs.c (wersja 9417)
+--- allcodecs.c (wersja 9451)
+++ allcodecs.c (kopia robocza)
@@ -92,6 +92,7 @@
REGISTER_DECODER(INDEO3, indeo3);
@@ -24,7 +24,7 @@ Index: allcodecs.c
REGISTER_ENCODER(LIBXVID, libxvid);
Index: allcodecs.h
===================================================================
---- allcodecs.h (wersja 9417)
+--- allcodecs.h (wersja 9451)
+++ allcodecs.h (kopia robocza)
@@ -40,6 +40,7 @@
extern AVCodec h264_encoder;
Modified: jpeg2000/j2k.h
==============================================================================
--- jpeg2000/j2k.h (original)
+++ jpeg2000/j2k.h Sat Jun 30 16:14:53 2007
@@ -29,6 +29,8 @@
#ifndef _J2K_H_
#define _J2K_H_
+#include "aec.h"
+
enum J2kMarkers{
J2K_SOC = 0xff4f,
J2K_SIZ = 0xff51,
@@ -53,79 +55,6 @@ enum J2kMarkers{
};
-/* arithmetic entropy coder context */
-//TODO: optimize [nice solution in openjpeg]
-typedef struct {
- unsigned int qe;
- unsigned int nmps;
- unsigned int nlps;
- unsigned int sw;
-} J2kAecState;
-
-const static J2kAecState aec_cx_states[47] = {
- {0x5601, 1, 1, 1},
- {0x3401, 2, 6, 0},
- {0x1801, 3, 9, 0},
- {0x0AC1, 4, 12, 0},
- {0x0521, 5, 29, 0},
- {0x0221, 38, 33, 0},
- {0x5601, 7, 6, 1},
- {0x5401, 8, 14, 0},
- {0x4801, 9, 14, 0},
- {0x3801, 10, 14, 0},
- {0x3001, 11, 17, 0},
- {0x2401, 12, 18, 0},
- {0x1C01, 13, 20, 0},
- {0x1601, 29, 21, 0},
- {0x5601, 15, 14, 1},
- {0x5401, 16, 14, 0},
- {0x5101, 17, 15, 0},
- {0x4801, 18, 16, 0},
- {0x3801, 19, 17, 0},
- {0x3401, 20, 18, 0},
- {0x3001, 21, 19, 0},
- {0x2801, 22, 19, 0},
- {0x2401, 23, 20, 0},
- {0x2201, 24, 21, 0},
- {0x1C01, 25, 22, 0},
- {0x1801, 26, 23, 0},
- {0x1601, 27, 24, 0},
- {0x1401, 28, 25, 0},
- {0x1201, 29, 26, 0},
- {0x1101, 30, 27, 0},
- {0x0AC1, 31, 28, 0},
- {0x09C1, 32, 29, 0},
- {0x08A1, 33, 30, 0},
- {0x0521, 34, 31, 0},
- {0x0441, 35, 32, 0},
- {0x02A1, 36, 33, 0},
- {0x0221, 37, 34, 0},
- {0x0141, 38, 35, 0},
- {0x0111, 39, 36, 0},
- {0x0085, 40, 37, 0},
- {0x0049, 41, 38, 0},
- {0x0025, 42, 39, 0},
- {0x0015, 43, 40, 0},
- {0x0009, 44, 41, 0},
- {0x0005, 45, 42, 0},
- {0x0001, 45, 43, 0},
- {0x5601, 46, 46, 0}
-};
-
-typedef struct {
- unsigned int state;
- unsigned int mps;
-} J2kAecContext;
-
-typedef struct {
- uint8_t *bp, *bpstart;
- unsigned int a;
- unsigned int c;
- unsigned int ct;
- J2kAecContext contexts[19];
- J2kAecContext *curctx;
-} J2kAec;
-
#define J2K_MAX_CBLKW 64
#define J2K_MAX_CBLKH 64
@@ -151,13 +80,10 @@ typedef struct {
#define J2K_T1_SIG 0x2000
#define J2K_T1_REF 0x4000
-#define J2K_T1_CTX_RL 17
-#define J2K_T1_CTX_UNI 18
-
typedef struct {
int data[J2K_MAX_CBLKW][J2K_MAX_CBLKH];
int flags[J2K_MAX_CBLKW+2][J2K_MAX_CBLKH+2];
- J2kAec aec;
+ AecState aec;
} J2kT1Context;
#endif
Modified: jpeg2000/j2kenc.c
==============================================================================
--- jpeg2000/j2kenc.c (original)
+++ jpeg2000/j2kenc.c Sat Jun 30 16:14:53 2007
@@ -639,139 +639,6 @@ static void dwt_encode53(J2kEncoderConte
av_free(ppu);
}
-/* arithmetic entropy coder routines: */
-static void aec_initenc(J2kAec *aec, uint8_t *bp)
-{
- bzero(aec->contexts, 19*sizeof(J2kAecContext));
- aec->contexts[J2K_T1_CTX_UNI].state = 46;
- aec->contexts[J2K_T1_CTX_RL].state = 3;
- aec->contexts[0].state = 4;
- aec->curctx = aec->contexts;
-
- aec->a = 0x8000;
- aec->c = 0;
- aec->bp = bp-1;
- aec->bpstart = bp;
- if (*aec->bp == 0xff)
- aec->ct = 13;
- else
- aec->ct = 12;
-}
-
-static void aec_byteout_l(J2kAec *aec)
-{
- aec->bp++;
- *aec->bp = aec->c >> 19;
- aec->c &= 0x7ffff;
- aec->ct = 8;
-}
-
-static void aec_byteout_r(J2kAec *aec)
-{
- aec->bp++;
- *aec->bp = aec->c >> 20;
- aec->c &= 0xfffff;
- aec->ct = 7;
-}
-
-static void aec_byteout(J2kAec *aec)
-{
- if (*aec->bp == 0xff){
- aec_byteout_r(aec);
- }
- else
- {
- if ((aec->c & 0x8000000) == 0){
- aec_byteout_l(aec);
- }
- else{
- (*aec->bp)++;
- if (*aec->bp == 0xff){
- aec->c &= 0x7ffffff;
- aec_byteout_r(aec);
- }
- else{
- aec_byteout_l(aec);
- }
- }
- }
-}
-
-static void aec_renorme(J2kAec *aec)
-{
- do{
- aec->a = aec->a << 1;
- aec->c = aec->c << 1;
- aec->ct--;
- if (!aec->ct)
- aec_byteout(aec);
- }
- while ((aec->a & 0x8000) == 0);
-}
-
-static void aec_codelps(J2kAec *aec)
-{
- int qe = aec_cx_states[aec->curctx->state].qe;
- aec->a -= qe;
- if (aec->a < qe)
- aec->c += qe;
- else
- aec->a = qe;
- if (aec_cx_states[aec->curctx->state].sw)
- aec->curctx->mps = 1 - aec->curctx->mps;
- aec->curctx->state = aec_cx_states[aec->curctx->state].nlps;
- aec_renorme(aec);
-}
-
-static void aec_codemps(J2kAec *aec)
-{
- int qe = aec_cx_states[aec->curctx->state].qe;
- aec->a -= qe;
- if ((aec->a & 0x8000) == 0){
- if (aec->a < qe)
- aec->a = qe;
- else
- aec->c += qe;
- aec->curctx->state = aec_cx_states[aec->curctx->state].nmps;
- aec_renorme(aec);
- }
- else
- aec->c += qe;
-}
-
-/* code bit d with context cx */
-static void aec_encode(J2kAec *aec, int cx, int d)
-{
- aec->curctx = aec->contexts + cx;
- if (aec->curctx->mps == d){
- aec_codemps(aec);
- }
- else{
- aec_codelps(aec);
- }
-}
-
-static void aec_setbits(J2kAec *aec)
-{
- int tmp = aec->c + aec->a;
- aec->c |= 0xffff;
- if (aec->c >= tmp)
- aec->c -= 0x8000;
-}
-
-/* flush the encoder [returns number of bytes encoded] */
-static int aec_flush(J2kAec *aec)
-{
- aec_setbits(aec);
- aec->c = aec->c << aec->ct;
- aec_byteout(aec);
- aec->c = aec->c << aec->ct;
- aec_byteout(aec);
- if (*aec->bp != 0xff)
- aec->bp++;
- return aec->bp - aec->bpstart;
-}
-
/* tier-1 routines */
static int getnbctxno(int flag, int bandno)
{
@@ -927,11 +794,11 @@ static void encode_clnpass(J2kT1Context
for (rlen = 0; rlen < 4; rlen++)
if (abs(t1->data[i+rlen][j]) & mask)
break;
- aec_encode(&t1->aec, J2K_T1_CTX_RL, rlen != 4);
+ aec_encode(&t1->aec, AEC_CX_RL, rlen != 4);
if (rlen == 4)
continue;
- aec_encode(&t1->aec, J2K_T1_CTX_UNI, rlen >> 1);
- aec_encode(&t1->aec, J2K_T1_CTX_UNI, rlen & 1);
+ aec_encode(&t1->aec, AEC_CX_UNI, rlen >> 1);
+ aec_encode(&t1->aec, AEC_CX_UNI, rlen & 1);
for (k = i + rlen; k < i + 4; k++){
if (!(t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS))){
int ctxno = getnbctxno(t1->flags[k+1][j+1], bandno);
3
2
Author: realsun
Date: Wed Jun 27 11:59:19 2007
New Revision: 283
Log:
adjust PES muxer structure, put PES payload construction out of it.
add prefix to non static functions.
Added:
dvbmuxer/pesenc.c
- copied, changed from r261, /dvbmuxer/pes.c
Modified:
dvbmuxer/pes.h
Modified: dvbmuxer/pes.h
==============================================================================
--- dvbmuxer/pes.h (original)
+++ dvbmuxer/pes.h Wed Jun 27 11:59:19 2007
@@ -1,5 +1,5 @@
/*
- * copyright (c) 2007 Xiaohui Sun <sunxiaohui(a)dsp.ac.cn>
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
@@ -39,16 +39,14 @@ typedef struct PacketDesc {
} PacketDesc;
typedef struct {
+ int is_ps; /*< whether it is a Program Stream */
int packet_number;
} PESContext;
typedef struct {
- uint8_t id;
AVFifoBuffer fifo;
- int max_buffer_size; /* in bytes */
+ int max_buffer_size; /*< in bytes */
int buffer_index;
- uint8_t lpcm_header[3];
- int lpcm_align;
PacketDesc *predecode_packet;
PacketDesc *premux_packet;
PacketDesc **next_packet;
@@ -77,14 +75,14 @@ static const int lpcm_freq_tab[4] = { 48
* @param[in] ctx the AVFormatContext which contains streams
* @return On error a negative value is returned, on success zero.
*/
-int pes_mux_init(AVFormatContext *ctx);
+int ff_pes_mux_init(AVFormatContext *ctx);
/*
* Finalization of PES mux.
* @param [in] ctx the AVFormatContext which contains streams.
* @return NULL
*/
-void pes_mux_end(AVFormatContext *ctx);
+void ff_pes_mux_end(AVFormatContext *ctx);
/*
* Write packet into PES fifo.
@@ -92,7 +90,7 @@ void pes_mux_end(AVFormatContext *ctx);
* @param [in] pkt the packet to write.
* @return NULL
*/
-void pes_write_packet(AVFormatContext *ctx, AVPacket *pkt);
+void ff_pes_write_packet(AVFormatContext *ctx, AVPacket *pkt);
/*
* Find the most fit stream to be muxed.
@@ -102,13 +100,21 @@ void pes_write_packet(AVFormatContext *c
* @param[out] best_i the best fit stream index
* @return On error a negative or zero value is returned, on success 1 is returned
*/
-int pes_find_beststream(AVFormatContext *ctx, int packet_size, int flush, int64_t scr, int* best_i);
+int ff_pes_find_beststream(AVFormatContext *ctx, int packet_size, int flush, int64_t scr, int* best_i);
+
+/*
+ * Get how many frames is muxed.
+ * @param[in] ctx the AVFormatContext
+ * @param[in] stream the PES stream
+ * @param[in] len PES packet size
+ * @return the frame number to be muxed
+ */
+int ff_get_nb_frames(AVFormatContext *ctx, PESStream *stream, int len);
/*
* Mux streams into a PES packet.
* @param [in] ctx the AVFormatContext which contains streams
* @param [in] stream_index the stream index to write
- * @param [in,out] q the stream to write
* @param [in] pts packet presentation time stamp
* @param [in] dts packet decoding time stamp
* @param [in] id stream id
@@ -120,17 +126,18 @@ int pes_find_beststream(AVFormatContext
* @param [in] trailer_size the trailer size of the packet
* @return bytes wirtten to PES stream.
*/
-int pes_mux_write(AVFormatContext *ctx, int stream_index, uint8_t* q,
+int ff_pes_mux_write(AVFormatContext *ctx, int stream_index,
int64_t pts,int64_t dts, int id, int startcode,
+ uint8_t* pes_content, int pes_content_len,
int header_len, int packet_size, int payload_size, int stuffing_size, int tailer_size);
/*
* Remove decoded packets of each stream.
* @param[in] ctx the AVFormatContext
* @param[in] scr System Clock Reference of PES stream.
- * @return NULL
+ * @return On error a negative or zero value is returned, on success 1 is returned
*/
-void pes_remove_decoded_packets(AVFormatContext *ctx, int64_t scr);
+int ff_pes_remove_decoded_packets(AVFormatContext *ctx, int64_t scr);
#endif/* PES_H */
Copied: dvbmuxer/pesenc.c (from r261, /dvbmuxer/pes.c)
==============================================================================
--- /dvbmuxer/pes.c (original)
+++ dvbmuxer/pesenc.c Wed Jun 27 11:59:19 2007
@@ -1,6 +1,6 @@
/*
* PES muxer.
- * Copyright (c) 2007 Xiaohui Sun <sunxiaohui(a)dsp.ac.cn>
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
*
* This file is part of FFmpeg.
*
@@ -20,94 +20,26 @@
*/
#include "pes.h"
-#include "bytestream.h"
-
-
-/*
- * Put timestamp into packet
- * @param[in] p the stream to write
- * @param[in] id stream id
- * @param[in] timestamp the timestamp to put in
- * @return NULL
- */
-static inline void put_timestamp(uint8_t* p, int id, int64_t timestamp)
-{
- bytestream_put_byte(&p,
- (id << 4) |
- (((timestamp >> 30) & 0x07) << 1) |
- 1);
- bytestream_put_be16(&p, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1));
- bytestream_put_be16(&p, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1));
-}
-static int get_nb_frames(AVFormatContext *ctx, PESStream *stream, int len){
- int nb_frames=0;
- PacketDesc *pkt_desc= stream->premux_packet;
-
- while(len>0){
- if(pkt_desc->size == pkt_desc->unwritten_size)
- nb_frames++;
- len -= pkt_desc->unwritten_size;
- pkt_desc= pkt_desc->next;
- }
-
- return nb_frames;
-}
-
-/*
- * Initialization of PES mux.
- * @param[in] ctx the AVFormatContext which contains streams
- * @return On error a negative value is returned, on success zero.
- */
-int pes_mux_init(AVFormatContext *ctx)
+int ff_pes_mux_init(AVFormatContext *ctx)
{
AVStream *st;
PESStream *stream;
- int i, j;
- int mpa_id, mpv_id, mps_id, ac3_id, dts_id, lpcm_id;
-
- mpa_id = AUDIO_ID;
- ac3_id = AC3_ID;
- dts_id = DTS_ID;
- mpv_id = VIDEO_ID;
- mps_id = SUB_ID;
- lpcm_id = LPCM_ID;
+ int i;
- for (i = 0; i < ctx->nb_streams; i++) {
+ for(i=0;i<ctx->nb_streams;i++) {
st = ctx->streams[i];
stream = (PESStream*)st->priv_data;
av_set_pts_info(st, 64, 1, 90000);
switch(st->codec->codec_type) {
case CODEC_TYPE_AUDIO:
- if (st->codec->codec_id == CODEC_ID_AC3) {
- stream->id = ac3_id++;
- } else if (st->codec->codec_id == CODEC_ID_DTS) {
- stream->id = dts_id++;
- } else if (st->codec->codec_id == CODEC_ID_PCM_S16BE) {
- stream->id = lpcm_id++;
- for(j = 0; j < 4; j++) {
- if (lpcm_freq_tab[j] == st->codec->sample_rate)
- break;
- }
- if (j == 4)
- return AVERROR(ENOMEM);
- if (st->codec->channels > 8)
- return -1;
- stream->lpcm_header[0] = 0x0c;
- stream->lpcm_header[1] = (st->codec->channels - 1) | (j << 4);
- stream->lpcm_header[2] = 0x80;
- stream->lpcm_align = st->codec->channels * 2;
- } else {
- stream->id = mpa_id++;
- }
/* This value HAS to be used for VCD (see VCD standard, p. IV-7).
- Right now it is also used for everything else.*/
+ Right now it is also used for everything else.*/
stream->max_buffer_size = 4 * 1024;
break;
case CODEC_TYPE_VIDEO:
- stream->id = mpv_id++;
#if 0
/* see VCD standard, p. IV-7*/
stream->max_buffer_size = 46 * 1024;
@@ -122,7 +54,6 @@ int pes_mux_init(AVFormatContext *ctx)
stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default
break;
case CODEC_TYPE_SUBTITLE:
- stream->id = mps_id++;
stream->max_buffer_size = 16 * 1024;
break;
default:
@@ -134,75 +65,121 @@ int pes_mux_init(AVFormatContext *ctx)
return 0;
}
-
-/*
- * Finalization of PES mux.
- * @param [in] ctx the AVFormatContext which contains streams.
- * @return NULL
- */
-void pes_mux_end(AVFormatContext *ctx)
+static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp)
{
- PESStream *stream;
- int i;
+ put_byte(pb,
+ (id << 4) |
+ (((timestamp >> 30) & 0x07) << 1) |
+ 1);
+ put_be16(pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1));
+ put_be16(pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1));
+}
- for (i = 0; i < ctx->nb_streams; i++) {
- stream = ctx->streams[i]->priv_data;
- assert(av_fifo_size(&stream->fifo) == 0);
- av_fifo_free(&stream->fifo);
+int ff_get_nb_frames(AVFormatContext *ctx, PESStream *stream, int len){
+ int nb_frames=0;
+ PacketDesc *pkt_desc= stream->premux_packet;
+
+ while(len>0){
+ if(pkt_desc->size == pkt_desc->unwritten_size)
+ nb_frames++;
+ len -= pkt_desc->unwritten_size;
+ pkt_desc= pkt_desc->next;
}
+
+ return nb_frames;
}
-/*
- * Write packet into PES fifo.
- * @param [in] ctx the AVFormatContext which contains streams.
- * @param [in] pkt the packet to write.
- * @return NULL
- */
-void pes_write_packet(AVFormatContext *ctx, AVPacket *pkt)
+int ff_pes_mux_write(AVFormatContext *ctx, int stream_index,
+ int64_t pts,int64_t dts, int id, int startcode,
+ uint8_t* pes_content, int pes_content_len,
+ int header_len, int packet_size, int payload_size, int stuffing_size, int trailer_size)
{
- int stream_index= pkt->stream_index;
- AVStream *st = ctx->streams[stream_index];
- PESStream *stream = st->priv_data;
- int size= pkt->size;
- uint8_t *buf= pkt->data;
- PacketDesc *pkt_desc;
- int64_t pts, dts;
- const int preload= av_rescale(ctx->preload, 90000, AV_TIME_BASE);
+ PESStream *stream = ctx->streams[stream_index]->priv_data;
+ PESContext *context = ctx->priv_data;
+ int pes_flags, i;
+ int data_size = payload_size - stuffing_size;
- pts= pkt->pts;
- dts= pkt->dts;
+ put_be32(&ctx->pb, startcode);
- if (pts != AV_NOPTS_VALUE)
- pts += preload;
- if (dts != AV_NOPTS_VALUE)
- dts += preload;
+ put_be16(&ctx->pb, packet_size);
+ put_byte(&ctx->pb, 0x80); /* mpeg2 id */
- if (!stream->premux_packet)
- stream->next_packet = &stream->premux_packet;
- *stream->next_packet=
- pkt_desc= av_mallocz(sizeof(PacketDesc));
- pkt_desc->pts= pkt->pts;
- pkt_desc->dts= pkt->dts;
- pkt_desc->unwritten_size=
- pkt_desc->size= size;
- if (!stream->predecode_packet)
- stream->predecode_packet= pkt_desc;
- stream->next_packet= &pkt_desc->next;
+ pes_flags=0;
- av_fifo_realloc(&stream->fifo, av_fifo_size(&stream->fifo) + size + 1);
- av_fifo_write(&stream->fifo, buf, size);
+ if (pts != AV_NOPTS_VALUE) {
+ pes_flags |= 0x80;
+ if (dts != pts)
+ pes_flags |= 0x40;
+ }
+
+ /* Both the MPEG-2 and the SVCD standards demand that the
+ P-STD_buffer_size field be included in the first packet of
+ every stream. (see SVCD standard p. 26 V.2.3.1 and V.2.3.2
+ and MPEG-2 standard 2.7.7) */
+ if (context->packet_number == 0 && context->is_ps)
+ pes_flags |= 0x01;
+
+ put_byte(&ctx->pb, pes_flags); /* flags */
+ put_byte(&ctx->pb, header_len - 3 + stuffing_size);
+
+ if (pes_flags & 0x80) /*write pts*/
+ put_timestamp(&ctx->pb, (pes_flags & 0x40) ? 0x03 : 0x02, pts);
+ if (pes_flags & 0x40) /*write dts*/
+ put_timestamp(&ctx->pb, 0x01, dts);
+
+ if (pes_flags & 0x01) { /*write pes extension*/
+ put_byte(&ctx->pb, 0x10); /* flags */
+
+ /* P-STD buffer info */
+ if (id == AUDIO_ID)
+ put_be16(&ctx->pb, 0x4000 | stream->max_buffer_size/128);
+ else
+ put_be16(&ctx->pb, 0x6000 | stream->max_buffer_size/1024);
+ }
+
+ /* special stuffing byte that is always written
+ to prevent accidental generation of start codes. */
+ put_byte(&ctx->pb, 0xff);
+
+ for (i=0;i<stuffing_size;i++)
+ put_byte(&ctx->pb, 0xff);
+
+ put_buffer(&ctx->pb, pes_content, pes_content_len);
+
+ /* output data */
+ if(av_fifo_generic_read(&stream->fifo, data_size, &put_buffer, &ctx->pb) < 0)
+ return -1;
+ return data_size;
}
+int ff_pes_remove_decoded_packets(AVFormatContext *ctx, int64_t scr)
+{
+ int i;
-/*
- * Find the most fit stream to be muxed.
- * @param[in] ctx the AVFormatContext
- * @param[in] packet_size the packet size of PES stream
- * @param[in] flush whether we flush after every single subtitle packet for subtitle
- * @param[out] best_i the best fit stream index
- * @return On error a negative or zero value is returned, on success 1 is returned
- */
-int pes_find_beststream(AVFormatContext *ctx, int packet_size, int flush, int64_t scr, int* best_i)
+ for(i=0; i<ctx->nb_streams; i++){
+ AVStream *st = ctx->streams[i];
+ PESStream *stream = st->priv_data;
+ PacketDesc *pkt_desc;
+
+ while((pkt_desc= stream->predecode_packet)
+ && scr > pkt_desc->dts){ //FIXME > vs >=
+ if(stream->buffer_index < pkt_desc->size ||
+ stream->predecode_packet == stream->premux_packet){
+ av_log(ctx, AV_LOG_ERROR,
+ "buffer underflow i=%d bufi=%d size=%d\n",
+ i, stream->buffer_index, pkt_desc->size);
+ break;
+ }
+ stream->buffer_index -= pkt_desc->size;
+ stream->predecode_packet= pkt_desc->next;
+ av_freep(&pkt_desc);
+ }
+ }
+ return 0;
+}
+
+
+int ff_pes_find_beststream(AVFormatContext *ctx, int packet_size, int flush, int64_t scr, int* best_i)
{
int best_score = INT_MIN;
int i, avail_space = 0;
@@ -210,61 +187,62 @@ int pes_find_beststream(AVFormatContext
const int64_t max_delay= av_rescale(ctx->max_delay, 90000, AV_TIME_BASE);
retry:
- for (i = 0; i < ctx->nb_streams; i++){
+ for(i=0; i<ctx->nb_streams; i++){
AVStream *st = ctx->streams[i];
PESStream*stream = st->priv_data;
- const int avail_data = av_fifo_size(&stream->fifo);
- const int space = stream->max_buffer_size - stream->buffer_index;
- int rel_space = 1024*space / stream->max_buffer_size;
- PacketDesc *next_pkt = stream->premux_packet;
+ const int avail_data= av_fifo_size(&stream->fifo);
+ const int space= stream->max_buffer_size - stream->buffer_index;
+ int rel_space= 1024*space / stream->max_buffer_size;
+ PacketDesc *next_pkt= stream->premux_packet;
/* for subtitle, a single PES packet must be generated,
- so we flush after every single subtitle packet */
- if (packet_size > avail_data && !flush
- && st->codec->codec_type != CODEC_TYPE_SUBTITLE)
+ so we flush after every single subtitle packet */
+ if(packet_size > avail_data && !flush
+ && st->codec->codec_type != CODEC_TYPE_SUBTITLE)
return 0;
- if (avail_data == 0)
+ if(avail_data==0)
continue;
- assert(avail_data > 0);
+ assert(avail_data>0);
- if (space < packet_size && !ignore_constraints)
+ if(space < packet_size && !ignore_constraints)
continue;
- if (next_pkt && next_pkt->dts - scr > max_delay)
+ if(next_pkt && next_pkt->dts - scr > max_delay)
continue;
- if (rel_space > best_score){
+ if(rel_space > best_score){
best_score= rel_space;
*best_i = i;
- avail_space = space;
+ avail_space= space;
}
}
- if (*best_i < 0){
- int64_t best_dts = INT64_MAX;
+ if(*best_i < 0){
+ int64_t best_dts= INT64_MAX;
- for (i = 0; i < ctx->nb_streams; i++){
- AVStream *st = ctx->streams[i];
- PESStream *stream = st->priv_data;
- PacketDesc *pkt_desc = stream->predecode_packet;
- if (pkt_desc && pkt_desc->dts < best_dts)
- best_dts = pkt_desc->dts;
+ for(i=0; i<ctx->nb_streams; i++){
+ AVStream *st = ctx->streams[i];
+ PESStream *stream = st->priv_data;
+ PacketDesc *pkt_desc= stream->predecode_packet;
+ if(pkt_desc && pkt_desc->dts < best_dts)
+ best_dts= pkt_desc->dts;
}
#if 0
av_log(ctx, AV_LOG_DEBUG, "bumping scr, scr:%f, dts:%f\n",
- scr/90000.0, best_dts/90000.0);
+ scr/90000.0, best_dts/90000.0);
#endif
- if (best_dts == INT64_MAX)
+ if(best_dts == INT64_MAX)
return 0;
- if (scr >= best_dts+1 && !ignore_constraints){
- av_log(ctx, AV_LOG_ERROR, "packet too large, ignoring buffer limits to mux it\n");
- ignore_constraints = 1;
+ if(scr >= best_dts+1 && !ignore_constraints){
+ av_log(ctx, AV_LOG_ERROR, "packet too large, ignoring buffer limits to mux it\n");
+ ignore_constraints= 1;
}
scr= FFMAX(best_dts+1, scr);
- pes_remove_decoded_packets(ctx, scr);
+ if(ff_pes_remove_decoded_packets(ctx, scr) < 0)
+ return -1;
goto retry;
}
assert(avail_space >= packet_size || ignore_constraints);
@@ -272,124 +250,48 @@ retry:
}
-/*
- * Mux streams into a PES packet.
- * @param [in] ctx the AVFormatContext which contains streams
- * @param [in] stream_index the stream index to write
- * @param [in,out] q the stream to write
- * @param [in] pts packet presentation time stamp
- * @param [in] dts packet decoding time stamp
- * @param [in] id stream id
- * @param [in] start_code PES packet start code
- * @param [in] header_len PES header size
- * @param [in] packet_size the total packet size
- * @param [in] payload_size the payload size of the packet
- * @param [in] stuffing_size the stuffing size of the packet
- * @param [in] trailer_size the trailer size of the packet
- * @return bytes wirtten to PES stream.
- */
-int pes_mux_write(AVFormatContext *ctx, int stream_index, uint8_t* q,
- int64_t pts,int64_t dts, int id, int startcode,
- int header_len, int packet_size, int payload_size, int stuffing_size, int trailer_size)
+void ff_pes_write_packet(AVFormatContext *ctx, AVPacket *pkt)
{
- PESStream *stream = ctx->streams[stream_index]->priv_data;
- PESContext *context = ctx->priv_data;
- int pes_flags, i, nb_frames;
- int data_size = payload_size - stuffing_size;
-
- bytestream_put_be32(&q, startcode);
- bytestream_put_be16(&q, packet_size);
- bytestream_put_byte(&q, 0x80); /* mpeg2 id */
-
- pes_flags=0;
-
- if (pts != AV_NOPTS_VALUE) {
- pes_flags |= 0x80;
- if (dts != pts)
- pes_flags |= 0x40;
- }
-
- /* Both the MPEG-2 and the SVCD standards demand that the
- P-STD_buffer_size field be included in the first packet of
- every stream. (see SVCD standard p. 26 V.2.3.1 and V.2.3.2
- and MPEG-2 standard 2.7.7) */
- if (context->packet_number == 0)
- pes_flags |= 0x01;
-
- bytestream_put_byte(&q, pes_flags);
- bytestream_put_byte(&q, header_len - 3 + stuffing_size);
-
- if (pes_flags & 0x80) /*write pts*/
- put_timestamp(q, (pes_flags & 0x40) ? 0x03 : 0x02, pts);
- if (pes_flags & 0x40) /*write dts*/
- put_timestamp(q, 0x01, dts);
-
- if (pes_flags & 0x01) { /*write pes extension*/
- bytestream_put_byte(&q, 0x10);
-
- /* P-STD buffer info */
- if (id == AUDIO_ID)
- bytestream_put_be16(&q, 0x4000 | stream ->max_buffer_size/128);
- else
- bytestream_put_be16(&q, 0x6000 | stream ->max_buffer_size/1024);
- }
+ int stream_index= pkt->stream_index;
+ AVStream *st = ctx->streams[stream_index];
+ PESStream *stream = st->priv_data;
+ PacketDesc *pkt_desc;
+ int size= pkt->size;
+ uint8_t *buf= pkt->data;
+ int64_t pts, dts;
+ const int preload= av_rescale(ctx->preload, 90000, AV_TIME_BASE);
- /* special stuffing byte that is always written
- to prevent accidental generation of start codes. */
- //put_byte(&ctx->pb, 0xff);
- bytestream_put_byte(&q, 0xff);
+ pts= pkt->pts;
+ dts= pkt->dts;
- for (i=0;i<stuffing_size;i++)
- bytestream_put_byte(&q, 0xff);
+ if(pts != AV_NOPTS_VALUE) pts += preload;
+ if(dts != AV_NOPTS_VALUE) dts += preload;
- if (startcode == PRIVATE_STREAM_1) {
- bytestream_put_byte(&q, id);
- if (id >= 0xa0) {
- /* LPCM (XXX: check nb_frames) */
- bytestream_put_byte(&q, 7);
- bytestream_put_be16(&q, 4); /* skip 3 header bytes */
- bytestream_put_byte(&q, stream->lpcm_header[0]);
- bytestream_put_byte(&q, stream->lpcm_header[1]);
- bytestream_put_byte(&q, stream->lpcm_header[2]);
- } else if (id >= 0x40) {
- /* AC3 */
- nb_frames= get_nb_frames(ctx, stream, data_size);
- bytestream_put_byte(&q, nb_frames);
- bytestream_put_be16(&q, trailer_size+1);
- }
- }
+ if (!stream->premux_packet)
+ stream->next_packet = &stream->premux_packet;
+ *stream->next_packet=
+ pkt_desc= av_mallocz(sizeof(PacketDesc));
+ pkt_desc->pts= pkt->pts;
+ pkt_desc->dts= pkt->dts;
+ pkt_desc->unwritten_size=
+ pkt_desc->size= size;
+ if(!stream->predecode_packet)
+ stream->predecode_packet= pkt_desc;
+ stream->next_packet= &pkt_desc->next;
- /* output data */
- if (av_fifo_read(&stream->fifo, q, data_size) < 0)
- return -1;
- q += data_size;
- return data_size;
+ av_fifo_realloc(&stream->fifo, av_fifo_size(&stream->fifo) + size + 1);
+ av_fifo_write(&stream->fifo, buf, size);
}
-/*
- * Remove decoded packets of each stream.
- * @param[in] ctx the AVFormatContext
- * @param[in] scr System Clock Reference of PES stream.
- * @return NULL
- */
-void pes_remove_decoded_packets(AVFormatContext *ctx, int64_t scr)
+
+void ff_pes_mux_end(AVFormatContext *ctx)
{
+ PESStream *stream;
int i;
- for (i = 0; i < ctx->nb_streams; i++){
- AVStream *st = ctx->streams[i];
- PESStream *stream = st->priv_data;
- PacketDesc *pkt_desc= stream->predecode_packet;
-
- while (pkt_desc && scr > pkt_desc->dts){ //FIXME > vs >=
- if (stream->buffer_index < pkt_desc->size ||
- stream->predecode_packet == stream->premux_packet){
- av_log(ctx, AV_LOG_ERROR, "buffer underflow\n");
- break;
- }
- stream->buffer_index -= pkt_desc->size;
- stream->predecode_packet= pkt_desc->next;
- av_freep(&pkt_desc);
- }
+ for(i=0;i<ctx->nb_streams;i++) {
+ stream = ctx->streams[i]->priv_data;
+ assert(av_fifo_size(&stream->fifo) == 0);
+ av_fifo_free(&stream->fifo);
}
}
2
1
Author: koorogi
Date: Sat Jun 30 19:11:22 2007
New Revision: 293
Log:
typo
Modified:
libavfilter/avfilter.c
Modified: libavfilter/avfilter.c
==============================================================================
--- libavfilter/avfilter.c (original)
+++ libavfilter/avfilter.c Sat Jun 30 19:11:22 2007
@@ -56,7 +56,7 @@ AVFilterPicRef *avfilter_default_get_vid
avpicture_alloc((AVPicture *)pic, pic->format, ref->w, ref->h);
memcpy(ref->data, pic->data, sizeof(uint8_t *) * 4);
- memcpy(ref->linesize, pic->linesize, sizeof(int *) * 4);
+ memcpy(ref->linesize, pic->linesize, sizeof(int) * 4);
return ref;
}
2
1
Author: koorogi
Date: Sat Jun 30 19:12:27 2007
New Revision: 294
Log:
Missed one usage of the AVFilterPic's linesize when making it a
per-AVFilterPicRef property.
Modified:
libavfilter/vf_crop.c
Modified: libavfilter/vf_crop.c
==============================================================================
--- libavfilter/vf_crop.c (original)
+++ libavfilter/vf_crop.c Sat Jun 30 19:12:27 2007
@@ -64,7 +64,7 @@ static void start_frame(AVFilterLink *li
ref2->w = crop->w;
ref2->h = crop->h;
- ref2->data[0] += crop->y * ref2->pic->linesize[0];
+ ref2->data[0] += crop->y * ref2->linesize[0];
ref2->data[0] += 3 * crop->x;
av_log(link->dst, AV_LOG_INFO, "start_frame()\n");
1
0
Author: koorogi
Date: Sat Jun 30 18:17:56 2007
New Revision: 292
Log:
Fix a pointer type
Modified:
libavfilter/avfilter.c
Modified: libavfilter/avfilter.c
==============================================================================
--- libavfilter/avfilter.c (original)
+++ libavfilter/avfilter.c Sat Jun 30 18:17:56 2007
@@ -55,7 +55,7 @@ AVFilterPicRef *avfilter_default_get_vid
pic->free = avfilter_default_free_video_buffer;
avpicture_alloc((AVPicture *)pic, pic->format, ref->w, ref->h);
- memcpy(ref->data, pic->data, sizeof(int *) * 4);
+ memcpy(ref->data, pic->data, sizeof(uint8_t *) * 4);
memcpy(ref->linesize, pic->linesize, sizeof(int *) * 4);
return ref;
1
0
Author: koorogi
Date: Fri Jun 29 19:03:03 2007
New Revision: 284
Log:
Initial stab at an API
Added:
libavfilter/
libavfilter/TODO
libavfilter/avfilter.c
libavfilter/avfilter.h
Added: libavfilter/TODO
==============================================================================
--- (empty file)
+++ libavfilter/TODO Fri Jun 29 19:03:03 2007
@@ -0,0 +1,37 @@
+FRAMEWORK:
+- colorspace negotiation
+- auto-inserting needed filters (colorspace conversion, buffer, etc)
+- parameter passing
+- pass pts, and whatever info is needed to reorder decode ordered frames
+- other useful image flags? interlace? top/bottom field first?
+- rework init sequence
+- ease reuse of same memory for multiple slices
+
+- proper vout filter support, with a display() callback?
+- support for running different filters in different threads?
+
+FILTERS:
+- make existing filters support more useful colorspaces (YUV)
+- colorspace conversion
+- scaling (combine with conversion like mplayer?)
+- (de)slicify
+- decode order -> display order
+- fifo buffer to buffer previous frames needed for next filter context
+- spatial context providing filter
+- picture-in-picture to test multiple inputs
+- splitter, feeding a single input to multiple filters to test multiple outputs
+- decimate to test non 1:1 input:output ratios
+- naive temporal blur to test buffering of previous frames
+- naive spatial blur to test spatial context
+- decoder/encoder wrapper
+
+- port vhook filters
+
+PROGRAMS:
+- make ffplay & ffmpeg support filters
+
+DOCUMENTATION:
+- more & better doxy comments
+- filter writing tutorial
+- filter using tutorial
+
Added: libavfilter/avfilter.c
==============================================================================
--- (empty file)
+++ libavfilter/avfilter.c Fri Jun 29 19:03:03 2007
@@ -0,0 +1,268 @@
+/*
+ * Filter layer
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "avfilter.h"
+
+/** list of registered filters, sorted by name */
+static int filter_count = 0;
+static AVFilter **filters = NULL;
+
+/* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */
+void avfilter_default_free_video_buffer(AVFilterPic *pic)
+{
+ avpicture_free((AVPicture *) pic);
+ av_free(pic);
+}
+
+/* TODO: set the buffer's priv member to a context structure for the whole
+ * filter chain. This will allow for a buffer pool instead of the constant
+ * alloc & free cycle currently implemented. */
+AVFilterPicRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms)
+{
+ AVFilterPic *pic = av_mallocz(sizeof(AVFilterPic));
+ AVFilterPicRef *ref = av_mallocz(sizeof(AVFilterPicRef));
+
+ ref->pic = pic;
+ ref->w = link->w;
+ ref->h = link->h;
+ ref->perms = perms;
+
+ pic->refcount = 1;
+ pic->format = link->format;
+ pic->free = avfilter_default_free_video_buffer;
+ avpicture_alloc((AVPicture *)pic, pic->format, ref->w, ref->h);
+
+ ref->data[0] = pic->data[0];
+ ref->data[1] = pic->data[1];
+ ref->data[2] = pic->data[2];
+ ref->data[3] = pic->data[3];
+
+ return ref;
+}
+
+void avfilter_default_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
+{
+ link->cur_pic = picref;
+}
+
+void avfilter_default_end_frame(AVFilterLink *link)
+{
+ avfilter_unref_pic(link->cur_pic);
+ link->cur_pic = NULL;
+}
+
+AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref)
+{
+ AVFilterPicRef *ret = av_malloc(sizeof(AVFilterPicRef));
+ memcpy(ret, ref, sizeof(AVFilterPicRef));
+ ret->pic->refcount ++;
+ return ret;
+}
+
+void avfilter_unref_pic(AVFilterPicRef *ref)
+{
+ if(-- ref->pic->refcount == 0)
+ ref->pic->free(ref->pic);
+ av_free(ref);
+}
+
+int avfilter_link(AVFilterContext *src, unsigned srcpad,
+ AVFilterContext *dst, unsigned dstpad)
+{
+ AVFilterLink *link;
+
+ if(src->outputs[srcpad] || dst->inputs[dstpad])
+ return -1;
+
+ src->outputs[srcpad] =
+ dst->inputs[dstpad] = link = av_malloc(sizeof(AVFilterLink));
+
+ link->src = src;
+ link->dst = dst;
+ link->srcpad = srcpad;
+ link->dstpad = dstpad;
+ link->cur_pic = NULL;
+
+ src->filter->outputs[dstpad].set_video_props(link);
+ return 0;
+}
+
+AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms)
+{
+ AVFilterPicRef *ret = NULL;
+
+ if(link->dst->filter->inputs[link->dstpad].get_video_buffer)
+ ret = link->dst->filter->inputs[link->dstpad].get_video_buffer(link, perms);
+
+ if(!ret)
+ ret = avfilter_default_get_video_buffer(link, perms);
+
+ return ret;
+}
+
+void avfilter_request_frame(AVFilterLink *link)
+{
+ link->src->filter->outputs[link->srcpad].request_frame(link);
+}
+
+/* XXX: should we do the duplicating of the picture ref here, instead of
+ * forcing the source filter to do it? */
+void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
+{
+ void (*start_frame)(AVFilterLink *, AVFilterPicRef *);
+
+ start_frame = link->dst->filter->inputs[link->dstpad].start_frame;
+ if(!start_frame)
+ start_frame = avfilter_default_start_frame;
+
+ start_frame(link, picref);
+}
+
+void avfilter_end_frame(AVFilterLink *link)
+{
+ void (*end_frame)(AVFilterLink *);
+
+ end_frame = link->dst->filter->inputs[link->dstpad].end_frame;
+ if(!end_frame)
+ end_frame = avfilter_default_end_frame;
+
+ end_frame(link);
+}
+
+void avfilter_draw_slice(AVFilterLink *link, uint8_t *data[4], int y, int h)
+{
+ link->dst->filter->inputs[link->dstpad].draw_slice(link, data, y, h);
+}
+
+static int filter_cmp(const void *aa, const void *bb)
+{
+ const AVFilter *a = *(const AVFilter **)aa, *b = *(const AVFilter **)bb;
+ return strcmp(a->name, b->name);
+}
+
+AVFilter *avfilter_get_by_name(char *name)
+{
+ AVFilter key = { .name = name, };
+ AVFilter *key2 = &key;
+ AVFilter **ret;
+
+ ret = bsearch(&key2, filters, filter_count, sizeof(AVFilter **), filter_cmp);
+ if(ret)
+ return *ret;
+ return NULL;
+}
+
+/* FIXME: insert in order, rather than insert at end + resort */
+void avfilter_register(AVFilter *filter)
+{
+ filters = av_realloc(filters, sizeof(AVFilter*) * (filter_count+1));
+ filters[filter_count] = filter;
+ qsort(filters, ++filter_count, sizeof(AVFilter **), filter_cmp);
+}
+
+void avfilter_init(void)
+{
+}
+
+void avfilter_uninit(void)
+{
+ av_freep(&filters);
+ filter_count = 0;
+}
+
+static int pad_count(const AVFilterPad *pads)
+{
+ AVFilterPad *p = (AVFilterPad *) pads;
+ int count;
+
+ for(count = 0; p->name; count ++) p ++;
+ return count;
+}
+
+static const char *filter_name(void *p)
+{
+ AVFilterContext *filter = p;
+ return filter->filter->name;
+}
+
+AVFilterContext *avfilter_create(AVFilter *filter)
+{
+ AVFilterContext *ret = av_malloc(sizeof(AVFilterContext));
+
+ ret->av_class = av_mallocz(sizeof(AVClass));
+ ret->av_class->item_name = filter_name;
+ ret->filter = filter;
+ ret->inputs = av_mallocz(sizeof(AVFilterLink*) * pad_count(filter->inputs));
+ ret->outputs = av_mallocz(sizeof(AVFilterLink*) * pad_count(filter->outputs));
+ ret->priv = av_mallocz(filter->priv_size);
+
+ return ret;
+}
+
+void avfilter_destroy(AVFilterContext *filter)
+{
+ int i;
+
+ if(filter->filter->uninit)
+ filter->filter->uninit(filter);
+
+ for(i = 0; i < pad_count(filter->filter->inputs); i ++) {
+ if(filter->inputs[i])
+ filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL;
+ av_free(filter->inputs[i]);
+ }
+ for(i = 0; i < pad_count(filter->filter->outputs); i ++) {
+ if(filter->outputs[i])
+ filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL;
+ av_free(filter->outputs[i]);
+ }
+
+ av_free(filter->inputs);
+ av_free(filter->outputs);
+ av_free(filter->priv);
+ av_free(filter->av_class);
+ av_free(filter);
+}
+
+AVFilterContext *avfilter_create_by_name(char *name)
+{
+ AVFilter *filt;
+
+ if(!(filt = avfilter_get_by_name(name))) return NULL;
+ return avfilter_create(filt);
+}
+
+int avfilter_init_filter(AVFilterContext *filter)
+{
+ int ret, i;
+
+ if(filter->filter->init)
+ if((ret = filter->filter->init(filter))) return ret;
+ for(i = 0; i < pad_count(filter->filter->outputs); i ++)
+ if(filter->outputs[i])
+ filter->filter->outputs[i].set_video_props(filter->outputs[i]);
+ return 0;
+}
+
Added: libavfilter/avfilter.h
==============================================================================
--- (empty file)
+++ libavfilter/avfilter.h Fri Jun 29 19:03:03 2007
@@ -0,0 +1,203 @@
+/*
+ * Filter layer
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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_AVFILTER_H
+#define FFMPEG_AVFILTER_H
+
+#include "avcodec.h"
+
+typedef struct AVFilterContext AVFilterContext;
+typedef struct AVFilterLink AVFilterLink;
+typedef struct AVFilterPad AVFilterPad;
+
+/* TODO: look for other flags which may be useful in this structure (interlace
+ * flags, etc)
+ */
+/**
+ * A reference-counted picture data type used by the filter system. Filters
+ * should not store pointers to this structure directly, but instead use the
+ * AVFilterPicRef structure below
+ */
+typedef struct AVFilterPic
+{
+ uint8_t *data[4];
+ int linesize[4]; ///< number of bytes per line
+ enum PixelFormat format;
+
+ unsigned refcount;
+ void *priv;
+ void (*free)(struct AVFilterPic *pic);
+} AVFilterPic;
+
+/**
+ * A reference to an AVFilterPic. Since filters can manipulate the origin of
+ * a picture to, for example, crop image without any memcpy, the picture origin
+ * and dimensions are per-reference properties.
+ *
+ * TODO: add pts, and anything necessary for frame reordering
+ */
+typedef struct AVFilterPicRef
+{
+ AVFilterPic *pic;
+ uint8_t *data[4];
+ int w, h;
+
+ int perms; ///< permissions
+#define AV_PERM_READ 0x01 ///< can read from the buffer
+#define AV_PERM_WRITE 0x02 ///< can write to the buffer
+#define AV_PERM_PRESERVE 0x04 ///< nobody else can overwrite the buffer
+#define AV_PERM_REUSE 0x08 ///< can output the buffer multiple times
+} AVFilterPicRef;
+
+/**
+ * Add a new reference to a picture.
+ * @param ref An existing reference to the picture
+ * @return A new reference to the picture with the same properties as the old
+ */
+AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref);
+
+/**
+ * Remove a reference to a picture. If this is the last reference to the
+ * picture, the picture itself is also automatically freed.
+ * @param ref Reference to the picture.
+ */
+void avfilter_unref_pic(AVFilterPicRef *ref);
+
+struct AVFilterPad
+{
+ /**
+ * Pad name. The name is unique among inputs and among oututs, but an
+ * input may have the same name as an output.
+ */
+ char *name;
+
+ /**
+ * AVFilterPad type. Only video supported now, hopefully someone will
+ * add audio in the future.
+ */
+ int type;
+#define AV_PAD_VIDEO 0
+
+ /**
+ * Callback called before passing the first slice of a new frame. If
+ * NULL, the filter layer will default to storing a reference to the
+ * picture inside the link structure.
+ */
+ void (*start_frame)(AVFilterLink *link, AVFilterPicRef *picref);
+
+ /**
+ * Callback function to get a buffer. If NULL, the filter system will
+ * handle buffer requests. Only required for input video pads.
+ */
+ AVFilterPicRef *(*get_video_buffer)(AVFilterLink *link, int perms);
+
+ /**
+ * Callback called after the slices of a frame are completely sent. If
+ * NULL, the filter layer will default to releasing the reference stored
+ * in the link structure during start_frame().
+ */
+ void (*end_frame)(AVFilterLink *link);
+
+ /**
+ * Slice drawing callback. This is where a filter receives video data
+ * and should do its processing. Only required for input video pads.
+ */
+ void (*draw_slice)(AVFilterLink *link, uint8_t *data[4], int y, int height);
+
+ /**
+ * Frame request callback. A call to this should result in at least one
+ * frame being output over the given link. Video output pads only.
+ */
+ void (*request_frame)(AVFilterLink *link);
+
+ /**
+ * Callback to set properties of the link. Only for video output pads.
+ * XXX: this is not acceptable as is. it needs reworked to allow for
+ * negotiation of colorspace, etc.
+ */
+ int (*set_video_props)(AVFilterLink *link);
+};
+
+/* the default implementations of start_frame() and end_frame() */
+void avfilter_default_start_frame(AVFilterLink *link, AVFilterPicRef *picref);
+void avfilter_default_end_frame(AVFilterLink *link);
+
+typedef struct
+{
+ char *name;
+ char *author;
+
+ int priv_size;
+
+ int (*init)(AVFilterContext *ctx);
+ void (*uninit)(AVFilterContext *ctx);
+
+ const AVFilterPad *inputs; /// NULL terminated list of inputs. NULL if none
+ const AVFilterPad *outputs; /// NULL terminated list of outputs. NULL if none
+} AVFilter;
+
+struct AVFilterContext
+{
+ AVClass *av_class;
+
+ AVFilter *filter;
+
+ AVFilterLink **inputs;
+ AVFilterLink **outputs;
+
+ void *priv;
+};
+
+struct AVFilterLink
+{
+ AVFilterContext *src;
+ unsigned int srcpad;
+
+ AVFilterContext *dst;
+ unsigned int dstpad;
+
+ int w, h;
+ enum PixelFormat format;
+
+ AVFilterPicRef *cur_pic;
+};
+
+/** Link two filters together */
+int avfilter_link(AVFilterContext *src, unsigned srcpad,
+ AVFilterContext *dst, unsigned dstpad);
+
+AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms);
+void avfilter_request_frame(AVFilterLink *link);
+void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref);
+void avfilter_end_frame(AVFilterLink *link);
+void avfilter_draw_slice(AVFilterLink *link, uint8_t *data[4], int y, int h);
+
+void avfilter_init(void);
+void avfilter_uninit(void);
+void avfilter_register(AVFilter *filter);
+AVFilter *avfilter_get_by_name(char *name);
+
+AVFilterContext *avfilter_create(AVFilter *filter);
+AVFilterContext *avfilter_create_by_name(char *name);
+int avfilter_init_filter(AVFilterContext *filter);
+void avfilter_destroy(AVFilterContext *filter);
+
+#endif /* FFMPEG_AVFILTER_H */
3
2