Exemplo n.º 1
0
/*! \brief This function applies deinterlacing (only if needed) and color
	conversion to the video frame in fRawDecodedPicture.

	It is assumed that fRawDecodedPicture wasn't deinterlaced and color
	converted yet (otherwise this function behaves in unknown manners).

	You should only call this function when you	got a new picture decoded by
	the video decoder and the fHeader variable was updated accordingly (\see
	_UpdateMediaHeaderForVideoFrame()).

	When this function finishes the postprocessed video frame will be available
	in fPostProcessedDecodedPicture and fDecodedData (fDecodedDataSizeInBytes
	will be set accordingly).
*/
void
AVCodecDecoder::_DeinterlaceAndColorConvertVideoFrame()
{
	int displayWidth = fHeader.u.raw_video.display_line_width;
	int displayHeight = fHeader.u.raw_video.display_line_count;
	AVPicture deinterlacedPicture;
	bool useDeinterlacedPicture = false;

	if (fRawDecodedPicture->interlaced_frame) {
		AVPicture rawPicture;
		rawPicture.data[0] = fRawDecodedPicture->data[0];
		rawPicture.data[1] = fRawDecodedPicture->data[1];
		rawPicture.data[2] = fRawDecodedPicture->data[2];
		rawPicture.data[3] = fRawDecodedPicture->data[3];
		rawPicture.linesize[0] = fRawDecodedPicture->linesize[0];
		rawPicture.linesize[1] = fRawDecodedPicture->linesize[1];
		rawPicture.linesize[2] = fRawDecodedPicture->linesize[2];
		rawPicture.linesize[3] = fRawDecodedPicture->linesize[3];

		avpicture_alloc(&deinterlacedPicture, fContext->pix_fmt, displayWidth,
			displayHeight);

		if (avpicture_deinterlace(&deinterlacedPicture, &rawPicture,
				fContext->pix_fmt, displayWidth, displayHeight) < 0) {
			TRACE("[v] avpicture_deinterlace() - error\n");
		} else
			useDeinterlacedPicture = true;
	}

	// Some decoders do not set pix_fmt until they have decoded 1 frame
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
	if (fSwsContext == NULL) {
		fSwsContext = sws_getContext(displayWidth, displayHeight,
			fContext->pix_fmt, displayWidth, displayHeight,
			colorspace_to_pixfmt(fOutputColorSpace),
			SWS_FAST_BILINEAR, NULL, NULL, NULL);
	}
#else
	if (fFormatConversionFunc == NULL) {
		fFormatConversionFunc = resolve_colorspace(fOutputColorSpace,
			fContext->pix_fmt, displayWidth, displayHeight);
	}
#endif

	fDecodedDataSizeInBytes = avpicture_get_size(
		colorspace_to_pixfmt(fOutputColorSpace), displayWidth, displayHeight);

	if (fDecodedData == NULL)
		fDecodedData
			= static_cast<uint8_t*>(malloc(fDecodedDataSizeInBytes));

	fPostProcessedDecodedPicture->data[0] = fDecodedData;
	fPostProcessedDecodedPicture->linesize[0]
		= fHeader.u.raw_video.bytes_per_row;

#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
	if (fSwsContext != NULL) {
#else
	if (fFormatConversionFunc != NULL) {
#endif
		if (useDeinterlacedPicture) {
			AVFrame deinterlacedFrame;
			deinterlacedFrame.data[0] = deinterlacedPicture.data[0];
			deinterlacedFrame.data[1] = deinterlacedPicture.data[1];
			deinterlacedFrame.data[2] = deinterlacedPicture.data[2];
			deinterlacedFrame.data[3] = deinterlacedPicture.data[3];
			deinterlacedFrame.linesize[0]
				= deinterlacedPicture.linesize[0];
			deinterlacedFrame.linesize[1]
				= deinterlacedPicture.linesize[1];
			deinterlacedFrame.linesize[2]
				= deinterlacedPicture.linesize[2];
			deinterlacedFrame.linesize[3]
				= deinterlacedPicture.linesize[3];

#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
			sws_scale(fSwsContext, deinterlacedFrame.data,
				deinterlacedFrame.linesize, 0, displayHeight,
				fPostProcessedDecodedPicture->data,
				fPostProcessedDecodedPicture->linesize);
#else
			(*fFormatConversionFunc)(&deinterlacedFrame,
				fPostProcessedDecodedPicture, displayWidth, displayHeight);
#endif
		} else {
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
			sws_scale(fSwsContext, fRawDecodedPicture->data,
				fRawDecodedPicture->linesize, 0, displayHeight,
				fPostProcessedDecodedPicture->data,
				fPostProcessedDecodedPicture->linesize);
#else
			(*fFormatConversionFunc)(fRawDecodedPicture,
				fPostProcessedDecodedPicture, displayWidth, displayHeight);
#endif
		}
	}

	if (fRawDecodedPicture->interlaced_frame)
		avpicture_free(&deinterlacedPicture);
}
status_t
AVCodecDecoder::_NegotiateVideoOutputFormat(media_format* inOutFormat)
{
	TRACE("AVCodecDecoder::_NegotiateVideoOutputFormat()\n");

	fOutputVideoFormat = fInputFormat.u.encoded_video.output;

	fContext->width = fOutputVideoFormat.display.line_width;
	fContext->height = fOutputVideoFormat.display.line_count;
//	fContext->frame_rate = (int)(fOutputVideoFormat.field_rate
//		* fContext->frame_rate_base);

	fOutputFrameRate = fOutputVideoFormat.field_rate;

	fContext->extradata = (uint8_t*)fExtraData;
	fContext->extradata_size = fExtraDataSize;

	TRACE("  requested video format 0x%x\n",
		inOutFormat->u.raw_video.display.format);

	// Make MediaPlayer happy (if not in rgb32 screen depth and no overlay,
	// it will only ask for YCbCr, which DrawBitmap doesn't handle, so the
	// default colordepth is RGB32).
	if (inOutFormat->u.raw_video.display.format == B_YCbCr422)
		fOutputVideoFormat.display.format = B_YCbCr422;
	else
		fOutputVideoFormat.display.format = B_RGB32;

	// Search for a pixel-format the codec handles
	// TODO: We should try this a couple of times until it succeeds, each
	// time using another pixel-format that is supported by the decoder.
	// But libavcodec doesn't seem to offer any way to tell the decoder
	// which format it should use.
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
	if (fSwsContext != NULL)
		sws_freeContext(fSwsContext);
	fSwsContext = NULL;
#else
	fFormatConversionFunc = 0;
#endif
	// Iterate over supported codec formats
	for (int i = 0; i < 1; i++) {
		// close any previous instance
		if (fCodecInitDone) {
			fCodecInitDone = false;
			avcodec_close(fContext);
		}
		// TODO: Set n-th fContext->pix_fmt here
		if (avcodec_open(fContext, fCodec) >= 0) {
			fCodecInitDone = true;

#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
			fSwsContext = sws_getContext(fContext->width, fContext->height,
				fContext->pix_fmt, fContext->width, fContext->height,
				colorspace_to_pixfmt(fOutputVideoFormat.display.format),
				SWS_FAST_BILINEAR, NULL, NULL, NULL);
		}
#else
			fFormatConversionFunc = resolve_colorspace(
				fOutputVideoFormat.display.format, fContext->pix_fmt, 
				fContext->width, fContext->height);
		}
		if (fFormatConversionFunc != NULL)
			break;
#endif
	}