This commit does for AVOutputFormat what commit 20f972701806be20a77f808db332d9489343bb78 did for AVCodec: It adds a new type FFOutputFormat, moves all the internals of AVOutputFormat to it and adds a now reduced AVOutputFormat as first member. This does not affect/improve extensibility of both public or private fields for muxers (it is still a mess due to lavd). Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Signed-off-by: Anton Khirnov <anton@khirnov.net>
		
			
				
	
	
		
			151 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Various muxing utility functions
 | 
						|
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
 | 
						|
 *
 | 
						|
 * This file is part of FFmpeg.
 | 
						|
 *
 | 
						|
 * FFmpeg is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU Lesser General Public
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2.1 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * FFmpeg is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * Lesser General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General Public
 | 
						|
 * License along with FFmpeg; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
 */
 | 
						|
 | 
						|
#include "libavutil/dict.h"
 | 
						|
#include "libavutil/dict_internal.h"
 | 
						|
#include "libavutil/internal.h"
 | 
						|
#include "libavutil/log.h"
 | 
						|
#include "libavutil/mem.h"
 | 
						|
#include "libavutil/parseutils.h"
 | 
						|
#include "avformat.h"
 | 
						|
#include "avio.h"
 | 
						|
#include "internal.h"
 | 
						|
#include "mux.h"
 | 
						|
 | 
						|
#if FF_API_GET_END_PTS
 | 
						|
int64_t av_stream_get_end_pts(const AVStream *st)
 | 
						|
{
 | 
						|
    if (cffstream(st)->priv_pts) {
 | 
						|
        return cffstream(st)->priv_pts->val;
 | 
						|
    } else
 | 
						|
        return AV_NOPTS_VALUE;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id,
 | 
						|
                         int std_compliance)
 | 
						|
{
 | 
						|
    if (ofmt) {
 | 
						|
        unsigned int codec_tag;
 | 
						|
        if (ffofmt(ofmt)->query_codec)
 | 
						|
            return ffofmt(ofmt)->query_codec(codec_id, std_compliance);
 | 
						|
        else if (ofmt->codec_tag)
 | 
						|
            return !!av_codec_get_tag2(ofmt->codec_tag, codec_id, &codec_tag);
 | 
						|
        else if (codec_id == ofmt->video_codec ||
 | 
						|
                 codec_id == ofmt->audio_codec ||
 | 
						|
                 codec_id == ofmt->subtitle_codec)
 | 
						|
            return 1;
 | 
						|
    }
 | 
						|
    return AVERROR_PATCHWELCOME;
 | 
						|
}
 | 
						|
 | 
						|
int ff_format_shift_data(AVFormatContext *s, int64_t read_start, int shift_size)
 | 
						|
{
 | 
						|
    int ret;
 | 
						|
    int64_t pos, pos_end;
 | 
						|
    uint8_t *buf, *read_buf[2];
 | 
						|
    int read_buf_id = 0;
 | 
						|
    int read_size[2];
 | 
						|
    AVIOContext *read_pb;
 | 
						|
 | 
						|
    buf = av_malloc_array(shift_size, 2);
 | 
						|
    if (!buf)
 | 
						|
        return AVERROR(ENOMEM);
 | 
						|
    read_buf[0] = buf;
 | 
						|
    read_buf[1] = buf + shift_size;
 | 
						|
 | 
						|
    /* Shift the data: the AVIO context of the output can only be used for
 | 
						|
     * writing, so we re-open the same output, but for reading. It also avoids
 | 
						|
     * a read/seek/write/seek back and forth. */
 | 
						|
    avio_flush(s->pb);
 | 
						|
    ret = s->io_open(s, &read_pb, s->url, AVIO_FLAG_READ, NULL);
 | 
						|
    if (ret < 0) {
 | 
						|
        av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for shifting data\n", s->url);
 | 
						|
        goto end;
 | 
						|
    }
 | 
						|
 | 
						|
    /* mark the end of the shift to up to the last data we wrote, and get ready
 | 
						|
     * for writing */
 | 
						|
    pos_end = avio_tell(s->pb);
 | 
						|
    avio_seek(s->pb, read_start + shift_size, SEEK_SET);
 | 
						|
 | 
						|
    avio_seek(read_pb, read_start, SEEK_SET);
 | 
						|
    pos = avio_tell(read_pb);
 | 
						|
 | 
						|
#define READ_BLOCK do {                                                             \
 | 
						|
    read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], shift_size);  \
 | 
						|
    read_buf_id ^= 1;                                                               \
 | 
						|
} while (0)
 | 
						|
 | 
						|
    /* shift data by chunk of at most shift_size */
 | 
						|
    READ_BLOCK;
 | 
						|
    do {
 | 
						|
        int n;
 | 
						|
        READ_BLOCK;
 | 
						|
        n = read_size[read_buf_id];
 | 
						|
        if (n <= 0)
 | 
						|
            break;
 | 
						|
        avio_write(s->pb, read_buf[read_buf_id], n);
 | 
						|
        pos += n;
 | 
						|
    } while (pos < pos_end);
 | 
						|
    ret = ff_format_io_close(s, &read_pb);
 | 
						|
 | 
						|
end:
 | 
						|
    av_free(buf);
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary **options)
 | 
						|
{
 | 
						|
    if (!s->oformat)
 | 
						|
        return AVERROR(EINVAL);
 | 
						|
 | 
						|
    if (!(s->oformat->flags & AVFMT_NOFILE))
 | 
						|
        return s->io_open(s, &s->pb, url, AVIO_FLAG_WRITE, options);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int ff_parse_creation_time_metadata(AVFormatContext *s, int64_t *timestamp, int return_seconds)
 | 
						|
{
 | 
						|
    AVDictionaryEntry *entry;
 | 
						|
    int64_t parsed_timestamp;
 | 
						|
    int ret;
 | 
						|
    if ((entry = av_dict_get(s->metadata, "creation_time", NULL, 0))) {
 | 
						|
        if ((ret = av_parse_time(&parsed_timestamp, entry->value, 0)) >= 0) {
 | 
						|
            *timestamp = return_seconds ? parsed_timestamp / 1000000 : parsed_timestamp;
 | 
						|
            return 1;
 | 
						|
        } else {
 | 
						|
            av_log(s, AV_LOG_WARNING, "Failed to parse creation_time %s\n", entry->value);
 | 
						|
            return ret;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int ff_standardize_creation_time(AVFormatContext *s)
 | 
						|
{
 | 
						|
    int64_t timestamp;
 | 
						|
    int ret = ff_parse_creation_time_metadata(s, ×tamp, 0);
 | 
						|
    if (ret == 1)
 | 
						|
        return avpriv_dict_set_timestamp(&s->metadata, "creation_time", timestamp);
 | 
						|
    return ret;
 | 
						|
}
 |