コード例 #1
0
ファイル: riff.cpp プロジェクト: crawlingChaos/dosbox-x
int riff_stack_streamwrite(riff_stack *s,riff_chunk *c,const void *buf,size_t len) {
	if (s->write == NULL)
		return -1;

	if (c) {
		if (!c->wmode)
			return -1;

		/* once the data is written, you are not allowed to write any more */
		if (c->write_offset != 0)
			return -1;

		/* AVI chunks are limited to 2GB or less */
		if ((c->write_offset+len) >= 0x80000000LL)
			return -1;

		/* assume the write will complete and setup pointers now */
		c->read_offset = c->write_offset = len;
		c->data_length = (uint32_t)c->write_offset;
		c->absolute_data_length = (c->data_length + 1UL) & (~1UL);

		/* write the header NOW */
		riff_stack_header_sync(s,c);

		/* then write the data.
		 * the consequence of this design is that unlike riff_stack_write() the
		 * call is considered an absolute failure IF we were not able to write all
		 * the data to disk. We have to, the design of this code bets on it!
		 *
		 * NTS: We allow the caller to streamwrite NULL-length packets with buf=NULL and len=0 */
		if (buf != NULL) {
			int rd;

			if (s->seek(s,c->absolute_data_offset) != c->absolute_data_offset) return 0;
			rd = s->write(s,buf,len);

			/* if we were not able to write all data, well, too bad. update the header */
			if (rd < (int)len) {
				if (rd < 0) rd = 0;
				c->read_offset = c->write_offset = rd;
				c->data_length = (uint32_t)c->write_offset;
				c->absolute_data_length = (c->data_length + 1UL) & (~1UL);

				/* write the header NOW */
				riff_stack_header_sync(s,c);

				/* fail */
				return -1;
			}
		}

		/* we already wrote the header, and the caller is SUPPOSED to
		 * use this function ONCE for a RIFF chunk. Don't let riff_stack_pop()
		 * waste it's time lseek()'ing back to rewrite the header */
		c->disable_sync = 1;
	}
	else {
		abort(); /* TODO */
	}

	return len;
}
コード例 #2
0
/* NTS: this code makes no attempt to optimize chunk sizes and combine samples/frames---if you're
 *      stupid enough to call this routine with 4-byte long data then 4-byte long chunks is what
 *      you'll get, don't blame me if doing that overruns the allocated space set aside for the
 *      indexes. */
int avi_writer_stream_write(avi_writer *w,avi_writer_stream *s,void *data,size_t len,uint32_t flags) {
    avi_writer_stream_index *si;
    riff_chunk chunk;

    if (w == NULL || s == NULL)
        return 0;
    if (w->state != AVI_WRITER_STATE_BODY)
        return 0;

    /* calling this function with data == NULL is perfectly valid, it simply means no data */
    if (data == NULL)
        len = 0;

    /* make sure we're down into the 'movi' chunk */
    while (w->riff->current > 1)
        riff_stack_pop(w->riff);

    /* make sure this is the movi chunk */
    if (w->riff->current != 1)
        return 0;
    if (w->riff->top->fourcc != avi_riff_movi)
        return 0;

    if (w->enable_opendml) {
        /* if we're writing an OpenDML 2.0 compliant file, and we're approaching a movi size of 1GB,
         * then split the movi chunk and start another RIFF:AVIX */
        if (((unsigned long long)w->riff->top->write_offset + (unsigned long long)len) >= 0x3FF00000ULL) { /* 1GB - 16MB */
            riff_stack_writing_sync(w->riff); /* sync all headers and pop all chunks */
            assert(w->riff->current == -1); /* should be at top level */

            /* at the first 1GB boundary emit AVIOLDINDEX for older AVI applications */
            if (w->group == 0 && w->enable_avioldindex)
                avi_writer_emit_avioldindex(w);

            /* [1] RIFF:AVIX */
            assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
            assert(riff_stack_set_chunk_list_type(&chunk,riff_RIFF,riff_fourcc_const('A','V','I','X')));
            if (w->enable_stream_writing) {
                assert(riff_stack_enable_placeholder(w->riff,&chunk));
                chunk.disable_sync = 1;
            }
            assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
            if (w->enable_stream_writing) riff_stack_header_sync(w->riff,riff_stack_top(w->riff));

            /* start the movi chunk */
            assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
            assert(riff_stack_set_chunk_list_type(&chunk,riff_LIST,riff_fourcc_const('m','o','v','i')));
            if (w->enable_stream_writing) {
                assert(riff_stack_enable_placeholder(w->riff,&chunk));
                chunk.disable_sync = 1;
            }
            assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
            if (w->enable_stream_writing) riff_stack_header_sync(w->riff,riff_stack_top(w->riff));
            w->movi = chunk;

            w->group++;
        }
    }
    else {
        /* else, if we're about to pass 2GB, then stop allowing any more data, because the traditional
         * AVI format uses 32-bit integers and most implementations treat them as signed. */
        if (((unsigned long long)w->movi.absolute_data_offset +
             (unsigned long long)w->riff->top->write_offset +
             (unsigned long long)len) >= 0x7FF00000ULL) /* 2GB - 16MB */
            return 0;
    }

    /* write chunk into movi */
    assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
    assert(riff_stack_set_chunk_data_type(&chunk,s->chunk_fourcc));
    assert(riff_stack_push(w->riff,&chunk));
    if (w->enable_stream_writing) {
        /* use an optimized version of riff_stack_write() that blasts the RIFF chunk header + data in one go */
        if (data != NULL && len > 0)
            assert((int)riff_stack_streamwrite(w->riff,riff_stack_top(w->riff),data,(size_t)len) == (int)len);
        else
            assert((int)riff_stack_streamwrite(w->riff,riff_stack_top(w->riff),NULL,(size_t)0) == (int)0);
    }
    else {
        if (data != NULL && len > 0)
            assert((int)riff_stack_write(w->riff,riff_stack_top(w->riff),data,(size_t)len) == (int)len);
    }
    riff_stack_pop(w->riff);

    /* put the data into the index */
    if (!avi_writer_stream_check_samplecount(s,s->sample_write_chunk+16))
        return 0;

    s->sample_index_max = s->sample_write_chunk+1;
    assert(s->sample_index_max < s->sample_index_alloc);
    si = s->sample_index + s->sample_write_chunk;

    si->stream_offset = s->sample_write_offset;
    si->offset = (uint64_t)chunk.absolute_data_offset;
    si->length = (uint32_t)len;
    si->dwFlags = flags;

    s->sample_write_offset += (unsigned int)len;
    s->sample_write_chunk++;

    /* if stream writing is not enabled, then rewrite all RIFF parent chunks to reflect the new data */
    if (!w->enable_stream_writing)
        riff_stack_header_sync_all(w->riff);

    return 1;
}
コード例 #3
0
ファイル: riff.cpp プロジェクト: crawlingChaos/dosbox-x
riff_chunk *riff_stack_pop(riff_stack *s) {
	riff_chunk *pc,*c;

	if (!s) return NULL;
	if (s->current == -1) return NULL;

	c = s->top;
	s->current--;
	if (s->current == -1) {
		if (s->wmode) {
			if (!c->disable_sync) riff_stack_header_sync(s,c);
			if (c->data_length < (int64_t)c->write_offset)
				c->data_length = (uint32_t)c->write_offset;

			c->absolute_data_length = (c->data_length + 1) & (~1UL);
			s->next_write = c->absolute_data_offset + c->absolute_data_length;
		}
		s->top = NULL;
		return NULL;
	}
	s->top = (s->stack + s->current);

	/* if we're writing a RIFF structure, we need to make sure
	 * the parent chunk's data offsets are properly set up.
	 * the above conditions ensure we don't get here unless
	 * there was a parent chunk involved */
	if (s->wmode) {
		unsigned char no_sync = c->disable_sync;

		if (c->placeholder) {
			c->placeholder = 0; /* caller pops a chunk off the stack to complete it, therefore the placeholder must be rewritten */
			c->disable_sync = 0; /* it MUST be rewritten, disabling sync is no longer an option */
			no_sync = 0; /* <--- ditto */
		}

		if (!no_sync) riff_stack_header_sync(s,c);
		pc = s->top;
		while (pc && c) {
			if ((c->absolute_data_offset + c->absolute_data_length) >
				(pc->absolute_data_offset + pc->data_length)) {
				pc->data_length = (uint32_t)((c->absolute_data_offset + c->absolute_data_length) -
					pc->absolute_data_offset);
				pc->absolute_data_length = pc->data_length; /* FIXME: right? */
			}

			if (c->absolute_data_offset >= pc->absolute_data_offset) {
				int64_t limit = c->absolute_data_offset + c->absolute_data_length -
					pc->absolute_data_offset;

				if (pc->write_offset < limit)
					pc->write_offset = limit;
			}

			if (pc == s->stack)
				break;

			c = pc--; /* NTS: remember pc = s->top = s->stack + <index> */
		}
		if (!no_sync) riff_stack_header_sync(s,s->top);
	}

	return s->top;
}
コード例 #4
0
int avi_writer_stream_repeat_last_chunk(avi_writer *w,avi_writer_stream *s) {
    avi_writer_stream_index *si,*psi;
    riff_chunk chunk;

    if (w == NULL || s == NULL)
        return 0;
    if (w->state != AVI_WRITER_STATE_BODY)
        return 0;
    if (s->sample_write_chunk == 0) /* if there *IS* no previous chunk, then bail */
        return 0;

    /* make sure we're down into the 'movi' chunk */
    while (w->riff->current > 1)
        riff_stack_pop(w->riff);

    /* make sure this is the movi chunk */
    if (w->riff->current != 1)
        return 0;
    if (w->riff->top->fourcc != avi_riff_movi)
        return 0;

    if (w->enable_opendml) {
        /* if we're writing an OpenDML 2.0 compliant file, and we're approaching a movi size of 1GB,
         * then split the movi chunk and start another RIFF:AVIX */
        if ((unsigned long long)(w->riff->top->write_offset + 8) >= 0x3FF00000ULL) { /* 1GB - 16MB */
            riff_stack_writing_sync(w->riff); /* sync all headers and pop all chunks */
            assert(w->riff->current == -1); /* should be at top level */

            /* at the first 1GB boundary emit AVIOLDINDEX for older AVI applications */
            if (w->group == 0 && w->enable_avioldindex)
                avi_writer_emit_avioldindex(w);

            /* [1] RIFF:AVIX */
            assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
            assert(riff_stack_set_chunk_list_type(&chunk,riff_RIFF,riff_fourcc_const('A','V','I','X')));
            if (w->enable_stream_writing) {
                assert(riff_stack_enable_placeholder(w->riff,&chunk));
                chunk.disable_sync = 1;
            }
            assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
            if (w->enable_stream_writing) riff_stack_header_sync(w->riff,riff_stack_top(w->riff));

            /* start the movi chunk */
            assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
            assert(riff_stack_set_chunk_list_type(&chunk,riff_LIST,riff_fourcc_const('m','o','v','i')));
            if (w->enable_stream_writing) {
                assert(riff_stack_enable_placeholder(w->riff,&chunk));
                chunk.disable_sync = 1;
            }
            assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
            if (w->enable_stream_writing) riff_stack_header_sync(w->riff,riff_stack_top(w->riff));
            w->movi = chunk;

            w->group++;
        }
    }
    else {
        /* else, if we're about to pass 2GB, then stop allowing any more data, because the traditional
         * AVI format uses 32-bit integers and most implementations treat them as signed. */
        if ((w->movi.absolute_data_offset + w->riff->top->write_offset + 8) >= 0x7FF00000LL) /* 2GB - 16MB */
            return 0;
    }

    /* write chunk into movi (for consistent timekeeping with older AVI apps that don't read the index) */
    assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
    assert(riff_stack_set_chunk_data_type(&chunk,s->chunk_fourcc));
    assert(riff_stack_push(w->riff,&chunk));
    riff_stack_pop(w->riff);

    /* put the data into the index */
    if (!avi_writer_stream_check_samplecount(s,s->sample_write_chunk+16))
        return 0;

    /* lookup the previous chunk */
    /* NTS: this must come after the check_samplecount() because check_samplecount()
     *      uses realloc() to extend the array and realloc() may move the data around
     *      to fullfill the request */
    assert(s->sample_index != NULL);
    assert(s->sample_index_max >= s->sample_write_chunk);
    psi = s->sample_index + s->sample_write_chunk - 1;

    s->sample_index_max = s->sample_write_chunk+1;
    assert(s->sample_index_max < s->sample_index_alloc);
    si = s->sample_index + s->sample_write_chunk;

    *si = *psi;
    si->stream_offset = s->sample_write_offset;

    s->sample_write_offset += si->length;
    s->sample_write_chunk++;
    riff_stack_header_sync_all(w->riff);
    return 1;
}