Exemple #1
0
static int libschroedinger_encode_frame(AVCodecContext *avccontext, AVPacket *pkt,
                                        const AVFrame *frame, int *got_packet)
{
    int enc_size = 0;
    SchroEncoderParams *p_schro_params = avccontext->priv_data;
    SchroEncoder *encoder = p_schro_params->encoder;
    struct FFSchroEncodedFrame *p_frame_output = NULL;
    int go = 1;
    SchroBuffer *enc_buf;
    int presentation_frame;
    int parse_code;
    int last_frame_in_sequence = 0;
    int pkt_size, ret;

    if (!frame) {
        /* Push end of sequence if not already signalled. */
        if (!p_schro_params->eos_signalled) {
            schro_encoder_end_of_stream(encoder);
            p_schro_params->eos_signalled = 1;
        }
    } else {
        /* Allocate frame data to schro input buffer. */
        SchroFrame *in_frame = libschroedinger_frame_from_data(avccontext,
                                                               frame);
        /* Load next frame. */
        schro_encoder_push_frame(encoder, in_frame);
    }

    if (p_schro_params->eos_pulled)
        go = 0;

    /* Now check to see if we have any output from the encoder. */
    while (go) {
        SchroStateEnum state;
        state = schro_encoder_wait(encoder);
        switch (state) {
        case SCHRO_STATE_HAVE_BUFFER:
        case SCHRO_STATE_END_OF_STREAM:
            enc_buf = schro_encoder_pull(encoder, &presentation_frame);
            assert(enc_buf->length > 0);
            assert(enc_buf->length <= buf_size);
            parse_code = enc_buf->data[4];

            /* All non-frame data is prepended to actual frame data to
             * be able to set the pts correctly. So we don't write data
             * to the frame output queue until we actually have a frame
             */
            p_schro_params->enc_buf = av_realloc(p_schro_params->enc_buf,
                                                 p_schro_params->enc_buf_size + enc_buf->length);

            memcpy(p_schro_params->enc_buf + p_schro_params->enc_buf_size,
                   enc_buf->data, enc_buf->length);
            p_schro_params->enc_buf_size += enc_buf->length;


            if (state == SCHRO_STATE_END_OF_STREAM) {
                p_schro_params->eos_pulled = 1;
                go = 0;
            }

            if (!SCHRO_PARSE_CODE_IS_PICTURE(parse_code)) {
                schro_buffer_unref(enc_buf);
                break;
            }

            /* Create output frame. */
            p_frame_output = av_mallocz(sizeof(FFSchroEncodedFrame));
            /* Set output data. */
            p_frame_output->size     = p_schro_params->enc_buf_size;
            p_frame_output->p_encbuf = p_schro_params->enc_buf;
            if (SCHRO_PARSE_CODE_IS_INTRA(parse_code) &&
                SCHRO_PARSE_CODE_IS_REFERENCE(parse_code))
                p_frame_output->key_frame = 1;

            /* Parse the coded frame number from the bitstream. Bytes 14
             * through 17 represesent the frame number. */
            p_frame_output->frame_num = AV_RB32(enc_buf->data + 13);

            ff_schro_queue_push_back(&p_schro_params->enc_frame_queue,
                                     p_frame_output);
            p_schro_params->enc_buf_size = 0;
            p_schro_params->enc_buf      = NULL;

            schro_buffer_unref(enc_buf);

            break;

        case SCHRO_STATE_NEED_FRAME:
            go = 0;
            break;

        case SCHRO_STATE_AGAIN:
            break;

        default:
            av_log(avccontext, AV_LOG_ERROR, "Unknown Schro Encoder state\n");
            return -1;
        }
    }

    /* Copy 'next' frame in queue. */

    if (p_schro_params->enc_frame_queue.size == 1 &&
        p_schro_params->eos_pulled)
        last_frame_in_sequence = 1;

    p_frame_output = ff_schro_queue_pop(&p_schro_params->enc_frame_queue);

    if (!p_frame_output)
        return 0;

    pkt_size = p_frame_output->size;
    if (last_frame_in_sequence && p_schro_params->enc_buf_size > 0)
        pkt_size += p_schro_params->enc_buf_size;
    if ((ret = ff_alloc_packet(pkt, pkt_size)) < 0) {
        av_log(avccontext, AV_LOG_ERROR, "Error getting output packet of size %d.\n", pkt_size);
        goto error;
    }

    memcpy(pkt->data, p_frame_output->p_encbuf, p_frame_output->size);
    avccontext->coded_frame->key_frame = p_frame_output->key_frame;
    /* Use the frame number of the encoded frame as the pts. It is OK to
     * do so since Dirac is a constant frame rate codec. It expects input
     * to be of constant frame rate. */
    pkt->pts =
    avccontext->coded_frame->pts = p_frame_output->frame_num;
    pkt->dts = p_schro_params->dts++;
    enc_size = p_frame_output->size;

    /* Append the end of sequence information to the last frame in the
     * sequence. */
    if (last_frame_in_sequence && p_schro_params->enc_buf_size > 0) {
        memcpy(pkt->data + enc_size, p_schro_params->enc_buf,
               p_schro_params->enc_buf_size);
        enc_size += p_schro_params->enc_buf_size;
        av_freep(&p_schro_params->enc_buf);
        p_schro_params->enc_buf_size = 0;
    }

    if (p_frame_output->key_frame)
        pkt->flags |= AV_PKT_FLAG_KEY;
    *got_packet = 1;

error:
    /* free frame */
    libschroedinger_free_frame(p_frame_output);
    return ret;
}
static bool
RunTest(int bit_depth)
{
	bool result = true;

	const int seq_len = 5;
	
	const int width = 100;
	const int height = 10;
	
	int luma_min = 16;
	int luma_max = 235;
	int chroma_zero = 128;
	
	schro_init();
	
	// set up encoder
	SchroEncoder *encoder = schro_encoder_new();
	
	schro_encoder_setting_set_double(encoder, "gop_structure", SCHRO_ENCODER_GOP_INTRA_ONLY);
	schro_encoder_setting_set_double(encoder, "rate_control", SCHRO_ENCODER_RATE_CONTROL_LOSSLESS);
	//schro_encoder_setting_set_double(encoder, "force_profile", SCHRO_ENCODER_PROFILE_VC2_SIMPLE);
	//schro_encoder_setting_set_double(encoder, "queue_depth", seq_len);
	//assert(seq_len <= SCHRO_LIMIT_FRAME_QUEUE_LENGTH);
	
	SchroVideoFormat *format = schro_encoder_get_video_format(encoder);
	
	if(format)
	{
		format->width = width;
		format->height = height;
		
		format->clean_width = format->width;
		format->clean_height = format->height;
		format->left_offset = 0;
		format->top_offset = 0;
		
		format->chroma_format = SCHRO_CHROMA_444;
		
		const SchroSignalRange range = (bit_depth == 12 ? SCHRO_SIGNAL_RANGE_12BIT_VIDEO :
										bit_depth == 10 ? SCHRO_SIGNAL_RANGE_10BIT_VIDEO :
										SCHRO_SIGNAL_RANGE_8BIT_VIDEO);
										
		schro_video_format_set_std_signal_range(format, range);
		
		luma_min = format->luma_offset;
		luma_max = format->luma_offset + format->luma_excursion;
		chroma_zero = format->chroma_offset;
		
		format->colour_primaries = SCHRO_COLOUR_PRIMARY_HDTV;
		format->colour_matrix = SCHRO_COLOUR_MATRIX_HDTV;
		format->transfer_function = SCHRO_TRANSFER_CHAR_TV_GAMMA;
		
		format->interlaced = false;
		
		format->frame_rate_numerator = 24;
		format->frame_rate_denominator = 1;
		
		format->aspect_ratio_numerator = 1;
		format->aspect_ratio_denominator = 1;
		
		schro_encoder_set_video_format(encoder, format);
		
		free(format);
	}
	else
		return false;
	
	schro_encoder_start(encoder);
	
	
	// create frame
	SchroFrame *start_frame = schro_frame_new_and_alloc(NULL, SCHRO_FRAME_FORMAT_U8_444, width, height);
	
	FillFrame<unsigned char>(start_frame, 16, 235, 128);
	
	const SchroFrameFormat schro_format = (bit_depth > 8 ? SCHRO_FRAME_FORMAT_S16_444 : SCHRO_FRAME_FORMAT_U8_444);

	SchroFrame *original_frame = schro_frame_new_and_alloc(NULL, schro_format, width, height);
	
	schro_frame_convert(original_frame, start_frame);
	
	
	
	SchroDecoder *decoder = schro_decoder_new();
	
	// push frames to encoder
	for(int t = 0; t < seq_len; t++)
	{
		SchroFrame *new_frame = schro_frame_dup(original_frame);
	
		schro_encoder_push_frame(encoder, new_frame);
	}
	
	
	
	// pull packets out of encoder, pass to decoder
	int packets_out = 0;
	
	while(packets_out < seq_len)
	{
		SchroStateEnum encoder_state = schro_encoder_wait(encoder);
		
		if(encoder_state == SCHRO_STATE_HAVE_BUFFER || encoder_state == SCHRO_STATE_END_OF_STREAM)
		{
			int n_decodable_frames = -1;
		
			SchroBuffer *buffer = schro_encoder_pull(encoder, &n_decodable_frames);
			
			if(buffer)
			{
				const int parse_code = buffer->data[4];
				
				if(SCHRO_PARSE_CODE_IS_SEQ_HEADER(parse_code) ||
					SCHRO_PARSE_CODE_IS_AUXILIARY_DATA(parse_code) ||
					SCHRO_PARSE_CODE_IS_PICTURE(parse_code))
				{
					schro_decoder_push(decoder, buffer);
					
					//schro_buffer_unref(buffer);
					
					if(SCHRO_PARSE_CODE_IS_PICTURE(parse_code))
					{
						packets_out++;
					}
				}
			}
		}
		else
		{
			assert(encoder_state == SCHRO_STATE_NEED_FRAME);
			assert(encoder_state != SCHRO_STATE_AGAIN); // yeah, redundant
		
			schro_encoder_end_of_stream(encoder);
		}
	}
	
	
	
	// pull frames out of decoder
	int frames_out = 0;
	
	while(frames_out < seq_len)
	{
		int decoder_state = schro_decoder_wait(decoder);
		
		if(decoder_state == SCHRO_DECODER_FIRST_ACCESS_UNIT)
		{
			SchroVideoFormat *format = schro_decoder_get_video_format(decoder);
			
			if(format)
			{
				assert(format->width == width);
				assert(format->height == height);
				
				assert(format->chroma_format == SCHRO_CHROMA_444);
				
				assert(format->luma_offset == luma_min);
				assert(format->luma_offset + format->luma_excursion == luma_max);
				assert(format->chroma_offset = chroma_zero);
				
				free(format);
			}
		}
		else if(decoder_state == SCHRO_DECODER_NEED_BITS)
		{
			schro_decoder_push_end_of_stream(decoder);
		}
		else if(decoder_state == SCHRO_DECODER_NEED_FRAME)
		{
			SchroFrame *decoder_frame = schro_frame_new_and_alloc(NULL, schro_format, width, height);
			
			schro_decoder_add_output_picture(decoder, decoder_frame);
		}
		else if(decoder_state == SCHRO_DECODER_OK || decoder_state == SCHRO_DECODER_EOS)
		{
			SchroFrame *decoder_frame = schro_decoder_pull(decoder);
			
			if(decoder_frame)
			{
				frames_out++;
			
				bool match = CompareFrames(decoder_frame, original_frame);
				
				//std::cout << (match ? "Match!" : "No Match!") << "  " << std::endl;
				
				if(!match)
				{
					// output doesn't match input, so print the values of the
					// first line of the first component to see what went in and out
					PrintFirstLine(original_frame);
					std::cout << "==========" << std::endl;
					PrintFirstLine(decoder_frame);
					std::cout << "==========" << std::endl;
				
					result = false;
				}
				
				schro_frame_unref(decoder_frame);
			}
		}
	}

	schro_frame_unref(original_frame);
	schro_frame_unref(start_frame);
	
	schro_decoder_free(decoder);
	schro_encoder_free(encoder);
	
	return result;
}