コード例 #1
0
OutputContext* output_context_new (const char * filename, const AVFrame * input_frame) {
    int ok = 0;

    // prepare muxer
    AVFormatContext * pfc = NULL;
    avformat_alloc_output_context2(&pfc, NULL, NULL, filename);
    if (!pfc) {
        goto failed;
    }

    // prepare encoding stream
    AVStream * pst = avformat_new_stream(pfc, NULL);
    if (!pst) {
        goto close_muxer;
    }

    // find encoder
    enum AVCodecID codec_id = av_guess_codec(pfc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO);
    if (codec_id == AV_CODEC_ID_NONE) {
        goto close_muxer;
    }
    AVCodec * pc = avcodec_find_encoder(codec_id);
    if (!pc) {
        goto close_muxer;
    }

    // prepare encoder
    AVCodecContext * pcc = avcodec_alloc_context3(pc);
    pcc->pix_fmt = pc->pix_fmts[0];
    pcc->codec_id = pc->id;
    pcc->codec_type = pc->type;
    pcc->time_base.num = 1;
    pcc->time_base.den = 1;
    pcc->width = input_frame->width;
    pcc->height = input_frame->height;
    ok = avcodec_open2(pcc, pc, NULL);
    if (ok != 0) {
        goto free_encoder;
    }

    ok = avcodec_parameters_from_context(pst->codecpar, pcc);
    if (ok < 0) {
        goto free_encoder;
    }

    OutputContext * context = malloc(sizeof(OutputContext));
    context->format_context = pfc;
    context->stream = pst;
    context->codec = pc;
    context->codec_context = pcc;

    return context;

free_encoder:
    avcodec_free_context(&pcc);
close_muxer:
    avformat_free_context(pfc);
failed:
    return NULL;
}
コード例 #2
0
ファイル: encode_lavc.c プロジェクト: Ionic/mpv
struct encode_lavc_context *encode_lavc_init(struct encode_opts *options,
                                             struct mpv_global *global)
{
    struct encode_lavc_context *ctx;
    const char *filename = options->file;

    // STUPID STUPID STUPID STUPID avio
    // does not support "-" as file name to mean stdin/stdout
    // ffmpeg.c works around this too, the same way
    if (!strcmp(filename, "-"))
        filename = "pipe:1";

    if (filename && (
            !strcmp(filename, "/dev/stdout") ||
            !strcmp(filename, "pipe:") ||
            !strcmp(filename, "pipe:1")))
        mp_msg_force_stderr(global, true);

    ctx = talloc_zero(NULL, struct encode_lavc_context);
    pthread_mutex_init(&ctx->lock, NULL);
    ctx->log = mp_log_new(ctx, global->log, "encode-lavc");
    ctx->global = global;
    encode_lavc_discontinuity(ctx);
    ctx->options = options;

    ctx->avc = avformat_alloc_context();

    if (ctx->options->format) {
        char *tok;
        const char *in = ctx->options->format;
        while (*in) {
            tok = av_get_token(&in, ",");
            ctx->avc->oformat = av_guess_format(tok, filename, NULL);
            av_free(tok);
            if (ctx->avc->oformat)
                break;
            if (*in)
                ++in;
        }
    } else
        ctx->avc->oformat = av_guess_format(NULL, filename, NULL);

    if (!ctx->avc->oformat) {
        encode_lavc_fail(ctx, "format not found\n");
        return NULL;
    }

    av_strlcpy(ctx->avc->filename, filename,
               sizeof(ctx->avc->filename));

    ctx->foptions = NULL;
    if (ctx->options->fopts) {
        char **p;
        for (p = ctx->options->fopts; *p; ++p) {
            if (!set_to_avdictionary(ctx, &ctx->foptions, NULL, *p))
                MP_WARN(ctx, "could not set option %s\n", *p);
        }
    }

    if (ctx->options->vcodec) {
        char *tok;
        const char *in = ctx->options->vcodec;
        while (*in) {
            tok = av_get_token(&in, ",");
            ctx->vc = avcodec_find_encoder_by_name(tok);
            av_free(tok);
            if (ctx->vc && ctx->vc->type != AVMEDIA_TYPE_VIDEO)
                ctx->vc = NULL;
            if (ctx->vc)
                break;
            if (*in)
                ++in;
        }
    } else
        ctx->vc = avcodec_find_encoder(av_guess_codec(ctx->avc->oformat, NULL,
                                                      ctx->avc->filename, NULL,
                                                      AVMEDIA_TYPE_VIDEO));

    if (ctx->options->acodec) {
        char *tok;
        const char *in = ctx->options->acodec;
        while (*in) {
            tok = av_get_token(&in, ",");
            ctx->ac = avcodec_find_encoder_by_name(tok);
            av_free(tok);
            if (ctx->ac && ctx->ac->type != AVMEDIA_TYPE_AUDIO)
                ctx->ac = NULL;
            if (ctx->ac)
                break;
            if (*in)
                ++in;
        }
    } else
        ctx->ac = avcodec_find_encoder(av_guess_codec(ctx->avc->oformat, NULL,
                                                      ctx->avc->filename, NULL,
                                                      AVMEDIA_TYPE_AUDIO));

    if (!ctx->vc && !ctx->ac) {
        encode_lavc_fail(
            ctx, "neither audio nor video codec was found\n");
        return NULL;
    }

    /* taken from ffmpeg unchanged
     * TODO turn this into an option if anyone needs this */

    ctx->avc->max_delay = 0.7 * AV_TIME_BASE;

    ctx->abytes = 0;
    ctx->vbytes = 0;
    ctx->frames = 0;

    if (options->video_first)
        ctx->video_first = true;
    if (options->audio_first)
        ctx->audio_first = true;

    return ctx;
}
コード例 #3
0
ファイル: encoder.c プロジェクト: icewwn/libgroove
int groove_encoder_attach(struct GrooveEncoder *encoder, struct GroovePlaylist *playlist) {
    struct GrooveEncoderPrivate *e = (struct GrooveEncoderPrivate *) encoder;

    encoder->playlist = playlist;
    groove_queue_reset(e->audioq);

    e->oformat = av_guess_format(encoder->format_short_name,
            encoder->filename, encoder->mime_type);
    if (!e->oformat) {
        groove_encoder_detach(encoder);
        av_log(NULL, AV_LOG_ERROR, "unable to determine format\n");
        return -1;
    }

    // av_guess_codec ignores mime_type, filename, and codec_short_name. see
    // https://trac.ffmpeg.org/ticket/4706
    // because of this we do a workaround to return the correct codec based on
    // the codec_short_name.
    AVCodec *codec = NULL;
    if (encoder->codec_short_name) {
        codec = avcodec_find_encoder_by_name(encoder->codec_short_name);
        if (!codec) {
            const AVCodecDescriptor *desc =
                avcodec_descriptor_get_by_name(encoder->codec_short_name);
            if (desc) {
                codec = avcodec_find_encoder(desc->id);
            }
        }
    }
    if (!codec) {
        enum AVCodecID codec_id = av_guess_codec(e->oformat,
                encoder->codec_short_name, encoder->filename, encoder->mime_type,
                AVMEDIA_TYPE_AUDIO);
        codec = avcodec_find_encoder(codec_id);
        if (!codec) {
            groove_encoder_detach(encoder);
            av_log(NULL, AV_LOG_ERROR, "unable to find encoder\n");
            return -1;
        }
    }
    e->codec = codec;
    av_log(NULL, AV_LOG_INFO, "encoder: using codec: %s\n", codec->long_name);

    encoder->actual_audio_format.sample_fmt = closest_supported_sample_fmt(
            codec, encoder->target_audio_format.sample_fmt);
    encoder->actual_audio_format.sample_rate = closest_supported_sample_rate(
            codec, encoder->target_audio_format.sample_rate);
    encoder->actual_audio_format.channel_layout = closest_supported_channel_layout(
            codec, encoder->target_audio_format.channel_layout);

    log_audio_fmt(&encoder->actual_audio_format);

    int err = init_avcontext(encoder);
    if (err < 0) {
        groove_encoder_detach(encoder);
        return err;
    }

    e->sink->audio_format = encoder->actual_audio_format;
    e->sink->buffer_size = encoder->sink_buffer_size;
    e->sink->buffer_sample_count = (codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) ?
        0 : e->stream->codec->frame_size;
    e->sink->gain = encoder->gain;

    if (groove_sink_attach(e->sink, playlist) < 0) {
        groove_encoder_detach(encoder);
        av_log(NULL, AV_LOG_ERROR, "unable to attach sink\n");
        return -1;
    }

    if (pthread_create(&e->thread_id, NULL, encode_thread, encoder) != 0) {
        groove_encoder_detach(encoder);
        av_log(NULL, AV_LOG_ERROR, "unable to create encoder thread\n");
        return -1;
    }

    return 0;
}
コード例 #4
0
ファイル: cvcap_ffmpeg.cpp プロジェクト: allanca/otterdive
/* add a video output stream to the container */
static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
		                                     CodecID codec_id,
											 int w, int h, int bitrate,
											 double fps, int pixel_format)
{
	AVCodecContext *c;
	AVStream *st;
	int frame_rate, frame_rate_base;
	AVCodec *codec;


	st = av_new_stream(oc, 0);
	if (!st) {
		CV_WARN("Could not allocate stream");
		return NULL;
	}

#if LIBAVFORMAT_BUILD > 4628
	c = st->codec;
#else
	c = &(st->codec);
#endif

#if LIBAVFORMAT_BUILD > 4621
	c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_VIDEO);
#else
	c->codec_id = oc->oformat->video_codec;
#endif

	if(codec_id != CODEC_ID_NONE){
		c->codec_id = codec_id;
	}

    //if(codec_tag) c->codec_tag=codec_tag;
	codec = avcodec_find_encoder(c->codec_id);

	c->codec_type = CODEC_TYPE_VIDEO;

	/* put sample parameters */
	c->bit_rate = bitrate;

	/* resolution must be a multiple of two */
	c->width = w;
	c->height = h;

	/* time base: this is the fundamental unit of time (in seconds) in terms
       of which frame timestamps are represented. for fixed-fps content,
       timebase should be 1/framerate and timestamp increments should be
       identically 1. */
	frame_rate=cvRound(fps);
	frame_rate_base=1;
	while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){
		frame_rate_base*=10;
		frame_rate=cvRound(fps*frame_rate_base);
	}
#if LIBAVFORMAT_BUILD > 4752
    c->time_base.den = frame_rate;
    c->time_base.num = frame_rate_base;
	/* adjust time base for supported framerates */
	if(codec && codec->supported_framerates){
		const AVRational *p= codec->supported_framerates;
        AVRational req = {frame_rate, frame_rate_base};
		const AVRational *best=NULL;
		AVRational best_error= {INT_MAX, 1};
		for(; p->den!=0; p++){
			AVRational error= av_sub_q(req, *p);
			if(error.num <0) error.num *= -1;
			if(av_cmp_q(error, best_error) < 0){
				best_error= error;
				best= p;
			}
		}
		c->time_base.den= best->num;
		c->time_base.num= best->den;
	}
#else
	c->frame_rate = frame_rate;
	c->frame_rate_base = frame_rate_base;
#endif

	c->gop_size = 12; /* emit one intra frame every twelve frames at most */
	c->pix_fmt = (PixelFormat) pixel_format;

	if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
        c->max_b_frames = 2;
    }
    if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3){
        /* needed to avoid using macroblocks in which some coeffs overflow
           this doesnt happen with normal video, it just happens here as the
           motion of the chroma plane doesnt match the luma plane */
		/* avoid FFMPEG warning 'clipping 1 dct coefficients...' */
        c->mb_decision=2;
    }
#if LIBAVCODEC_VERSION_INT>0x000409
    // some formats want stream headers to be seperate
    if(oc->oformat->flags & AVFMT_GLOBALHEADER)
    {
        c->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }
#endif

    return st;
}
コード例 #5
0
asynStatus ffmpegFile::openFile(const char *filename, NDFileOpenMode_t openMode, NDArray *pArray)
{
    int ret;
	static const char *functionName = "openFile";
	char errbuf[AV_ERROR_MAX_STRING_SIZE];
    epicsFloat64 f64Val;
    this->sheight = 0;
	this->swidth = 0;

    /* We don't support reading yet */
    if (openMode & NDFileModeRead) return(asynError);

    /* We don't support opening an existing file for appending yet */
    if (openMode & NDFileModeAppend) return(asynError);

    /* allocate the output media context */
    avformat_alloc_output_context2(&oc, NULL, NULL, filename);
    if (!oc) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s Could not deduce output format from file extension: using MPEG.\n",
            driverName2, functionName);
        avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);
    }
    if (!oc) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s Memory error: Cannot allocate output context\n",
            driverName2, functionName);
        return(asynError);
    }

    /* If we are using image2 then we only support one frame per image */
    fmt = oc->oformat;
    if (strcmp("image2", fmt->name)==0) {
    	this->supportsMultipleArrays = 0;
    } else {
    	this->supportsMultipleArrays = 1;
        /* We want to use msmpeg4v2 instead of mpeg4 for avi files*/
        if (av_match_ext(filename, "avi") && fmt->video_codec == AV_CODEC_ID_MPEG4) {
        	fmt->video_codec = AV_CODEC_ID_MSMPEG4V2;
        }
    }

    codec_id = av_guess_codec(fmt, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO);
    if (codec_id == AV_CODEC_ID_NONE) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s Codec has no video stream component\n",
            driverName2, functionName);
        return(asynError);
    }

    /* find the encoder */
    video_st = NULL;
    codec = avcodec_find_encoder(codec_id);
	if (!codec) {
		asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
					"%s:%s Could not find encoder for '%s'\n",
					driverName2, functionName, avcodec_get_name(codec_id));
		return(asynError);
	}

	/* Create the video stream */
	video_st = avformat_new_stream(oc, codec);
	if (!video_st) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s Could not allocate stream\n",
            driverName2, functionName);
        return(asynError);
	}
	video_st->id = oc->nb_streams-1;
	c = video_st->codec;

	if (codec->type != AVMEDIA_TYPE_VIDEO) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s Codec context is not of type AVMEDIA_TYPE_VIDEO\n",
            driverName2, functionName);
        return(asynError);
	}

	avcodec_get_context_defaults3(c, codec);
	c->codec_id = codec_id;

    /* put sample parameters */
    getDoubleParam(0, ffmpegFileBitrate, &f64Val);
    c->bit_rate = (int64_t)f64Val;

    /* frames per second */
    AVRational avr;
    avr.num = 1;
    getIntegerParam(0, ffmpegFileFPS, &(avr.den));

    /* resolution must be a multiple of two */
    getIntegerParam(0, ffmpegFileWidth, &(c->width));
    getIntegerParam(0, ffmpegFileHeight, &(c->height));
    /* time base: this is the fundamental unit of time (in seconds) in terms
       of which frame timestamps are represented. for fixed-fps content,
       timebase should be 1/framerate and timestamp increments should be
       identically 1. */
    c->time_base = avr;

	c->gop_size      = 12; /* emit one intra frame every twelve frames at most */

    c->pix_fmt = AV_PIX_FMT_YUV420P;
    if(codec && codec->pix_fmts){
        const enum AVPixelFormat *p= codec->pix_fmts;
        for(; *p!=-1; p++){
            if(*p == c->pix_fmt)
                break;
        }
        if(*p == -1)
            c->pix_fmt = codec->pix_fmts[0];
    }

	if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
		/* just for testing, we also add B frames */
		c->max_b_frames = 2;
	}
	if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
		/* Needed to avoid using macroblocks in which some coeffs overflow.
		 * This does not happen with normal video, it just happens here as
		 * the motion of the chroma plane does not match the luma plane. */
		c->mb_decision = 2;
	}

	/* Some formats want stream headers to be separate. */
	if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
		c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
	}

    /* Now that all the parameters are set, we can open the audio and
     * video codecs and allocate the necessary encode buffers. */

	c = video_st->codec;

	/* open the codec */
	ret = avcodec_open2(c, codec, NULL);
	if (ret < 0) {
		asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
		            "%s:%s Could not open video codec: %s\n",
		            driverName2, functionName, av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, ret));
		return(asynError);
	}

	/* dump the format so we can see it on the console... */
    av_dump_format(oc, 0, filename, 1);

    /* open the output file, if needed */
	ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
	if (ret < 0) {
		asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
							"%s:%s Could not open '%s': %s\n",
							driverName2, functionName, filename, av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, ret));
		return(asynError);
	}

    /* Write the stream header, if any. */
    ret = avformat_write_header(oc, NULL);
    if (ret < 0) {
		asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
				"%s:%s Error occurred when opening output file %s: %s\n",
							driverName2, functionName, filename, av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, ret));
		return(asynError);
    }

	outSize = c->width * c->height * 6;   

    /* alloc array for output and compression */
    if (scArray) {
    	scArray->release();
    	scArray = NULL;
    }
    if (outArray) {
    	outArray->release();
    	outArray = NULL;
    }

    scArray = this->pNDArrayPool->alloc(1, &outSize, NDInt8, 0, NULL);
    outArray = this->pNDArrayPool->alloc(1, &outSize, NDInt8, 0, NULL);
    if (scArray == NULL || outArray == NULL) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s error allocating arrays\n",
            driverName2, functionName);
        if (scArray) {
        	scArray->release();
        	scArray = NULL;
        }
        if (outArray) {
        	outArray->release();
        	outArray = NULL;
        }
        return(asynError);
    }

    /* alloc in and scaled pictures */
    inPicture = av_frame_alloc();
    scPicture = av_frame_alloc();
	avpicture_fill((AVPicture *)scPicture,(uint8_t *)scArray->pData,c->pix_fmt,c->width,c->height);       
    scPicture->pts = 0;
	needStop = 1;
    return(asynSuccess);

}