/*****************************************************************************
* utils.c: helper functions
*****************************************************************************
- * Copyright (C) 2010 the VideoLAN team
+ * Copyright (C) 2010 VLC authors and VideoLAN
* $Id$
*
* Authors: Gildas Bazin <gbazin@videolan.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program 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.
*
* This program 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 General Public License for more details.
+ * 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 General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
#include "omxil.h"
#include "qcom.h"
+#include "../../video_chroma/copy.h"
/*****************************************************************************
* Events utility functions
*****************************************************************************/
-OMX_ERRORTYPE PostOmxEvent(decoder_t *p_dec, OMX_EVENTTYPE event,
+void InitOmxEventQueue(OmxEventQueue *queue)
+{
+ queue->pp_last_event = &queue->p_events;
+ vlc_mutex_init(&queue->mutex);
+ vlc_cond_init(&queue->cond);
+}
+
+void DeinitOmxEventQueue(OmxEventQueue *queue)
+{
+ vlc_mutex_destroy(&queue->mutex);
+ vlc_cond_destroy(&queue->cond);
+}
+
+OMX_ERRORTYPE PostOmxEvent(OmxEventQueue *queue, OMX_EVENTTYPE event,
OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data)
{
- decoder_sys_t *p_sys = p_dec->p_sys;
OmxEvent *p_event;
p_event = malloc(sizeof(OmxEvent));
p_event->event_data = event_data;
p_event->next = 0;
- vlc_mutex_lock(&p_sys->mutex);
- *p_sys->pp_last_event = p_event;
- p_sys->pp_last_event = &p_event->next;
- vlc_cond_signal(&p_sys->cond);
- vlc_mutex_unlock(&p_sys->mutex);
+ vlc_mutex_lock(&queue->mutex);
+ *queue->pp_last_event = p_event;
+ queue->pp_last_event = &p_event->next;
+ vlc_cond_signal(&queue->cond);
+ vlc_mutex_unlock(&queue->mutex);
return OMX_ErrorNone;
}
-OMX_ERRORTYPE WaitForOmxEvent(decoder_t *p_dec, OMX_EVENTTYPE *event,
+OMX_ERRORTYPE WaitForOmxEvent(OmxEventQueue *queue, OMX_EVENTTYPE *event,
OMX_U32 *data_1, OMX_U32 *data_2, OMX_PTR *event_data)
{
- decoder_sys_t *p_sys = p_dec->p_sys;
OmxEvent *p_event;
- vlc_mutex_lock(&p_sys->mutex);
+ vlc_mutex_lock(&queue->mutex);
- if(!p_sys->p_events)
- vlc_cond_timedwait(&p_sys->cond, &p_sys->mutex, mdate()+CLOCK_FREQ);
+ if(!queue->p_events)
+ vlc_cond_timedwait(&queue->cond, &queue->mutex, mdate()+CLOCK_FREQ);
- p_event = p_sys->p_events;
+ p_event = queue->p_events;
if(p_event)
{
- p_sys->p_events = p_event->next;
- if(!p_sys->p_events) p_sys->pp_last_event = &p_sys->p_events;
+ queue->p_events = p_event->next;
+ if(!queue->p_events) queue->pp_last_event = &queue->p_events;
}
- vlc_mutex_unlock(&p_sys->mutex);
+ vlc_mutex_unlock(&queue->mutex);
if(p_event)
{
return OMX_ErrorTimeout;
}
-OMX_ERRORTYPE WaitForSpecificOmxEvent(decoder_t *p_dec,
+OMX_ERRORTYPE WaitForSpecificOmxEvent(OmxEventQueue *queue,
OMX_EVENTTYPE specific_event, OMX_U32 *data_1, OMX_U32 *data_2,
OMX_PTR *event_data)
{
while(1)
{
- status = WaitForOmxEvent(p_dec, &event, data_1, data_2, event_data);
+ status = WaitForOmxEvent(queue, &event, data_1, data_2, event_data);
if(status != OMX_ErrorNone) return status;
if(event == specific_event) break;
return OMX_ErrorNone;
}
+void PrintOmxEvent(vlc_object_t *p_this, OMX_EVENTTYPE event, OMX_U32 data_1,
+ OMX_U32 data_2, OMX_PTR event_data)
+{
+ switch (event)
+ {
+ case OMX_EventCmdComplete:
+ switch ((OMX_STATETYPE)data_1)
+ {
+ case OMX_CommandStateSet:
+ msg_Dbg( p_this, "OmxEventHandler (%s, %s, %s)", EventToString(event),
+ CommandToString(data_1), StateToString(data_2) );
+ break;
+
+ default:
+ msg_Dbg( p_this, "OmxEventHandler (%s, %s, %u)", EventToString(event),
+ CommandToString(data_1), (unsigned int)data_2 );
+ break;
+ }
+ break;
+
+ case OMX_EventError:
+ msg_Dbg( p_this, "OmxEventHandler (%s, %s, %u, %s)", EventToString(event),
+ ErrorToString((OMX_ERRORTYPE)data_1), (unsigned int)data_2,
+ (const char *)event_data);
+ break;
+
+ default:
+ msg_Dbg( p_this, "OmxEventHandler (%s, %u, %u)", EventToString(event),
+ (unsigned int)data_1, (unsigned int)data_2 );
+ break;
+ }
+}
+
/*****************************************************************************
* Picture utility functions
*****************************************************************************/
-void CopyOmxPicture( decoder_t *p_dec, picture_t *p_pic,
- OMX_BUFFERHEADERTYPE *p_header, int i_slice_height )
+void ArchitectureSpecificCopyHooks( decoder_t *p_dec, int i_color_format,
+ int i_slice_height, int i_src_stride,
+ ArchitectureSpecificCopyData *p_architecture_specific )
{
- decoder_sys_t *p_sys = p_dec->p_sys;
- int i_src_stride, i_dst_stride;
- int i_plane, i_width, i_line;
- uint8_t *p_dst, *p_src;
+ (void)i_slice_height;
- i_src_stride = p_sys->out.i_frame_stride;
- p_src = p_header->pBuffer + p_header->nOffset;
+#ifdef CAN_COMPILE_SSE2
+ if( i_color_format == OMX_COLOR_FormatYUV420SemiPlanar && vlc_CPU_SSE2() )
+ {
+ copy_cache_t *p_surface_cache = malloc( sizeof(copy_cache_t) );
+ if( !p_surface_cache || CopyInitCache( p_surface_cache, i_src_stride ) )
+ {
+ free( p_surface_cache );
+ return;
+ }
+ p_architecture_specific->data = p_surface_cache;
+ p_dec->fmt_out.i_codec = VLC_CODEC_YV12;
+ }
+#endif
+}
+
+void ArchitectureSpecificCopyHooksDestroy( int i_color_format,
+ ArchitectureSpecificCopyData *p_architecture_specific )
+{
+ if (!p_architecture_specific->data)
+ return;
+#ifdef CAN_COMPILE_SSE2
+ if( i_color_format == OMX_COLOR_FormatYUV420SemiPlanar && vlc_CPU_SSE2() )
+ {
+ copy_cache_t *p_surface_cache = (copy_cache_t*)p_architecture_specific->data;
+ CopyCleanCache(p_surface_cache);
+ }
+#endif
+ free(p_architecture_specific->data);
+ p_architecture_specific->data = NULL;
+}
- if( p_dec->p_sys->out.definition.format.video.eColorFormat == QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka )
+void CopyOmxPicture( int i_color_format, picture_t *p_pic,
+ int i_slice_height,
+ int i_src_stride, uint8_t *p_src, int i_chroma_div,
+ ArchitectureSpecificCopyData *p_architecture_specific )
+{
+ uint8_t *p_dst;
+ int i_dst_stride;
+ int i_plane, i_width, i_line;
+ if( i_color_format == QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka )
{
qcom_convert(p_src, p_pic);
return;
}
+#ifdef CAN_COMPILE_SSE2
+ if( i_color_format == OMX_COLOR_FormatYUV420SemiPlanar
+ && vlc_CPU_SSE2() && p_architecture_specific->data )
+ {
+ copy_cache_t *p_surface_cache = (copy_cache_t*)p_architecture_specific->data;
+ uint8_t *ppi_src_pointers[2] = { p_src, p_src + i_src_stride * i_slice_height };
+ size_t pi_src_strides[2] = { i_src_stride, i_src_stride };
+ CopyFromNv12( p_pic, ppi_src_pointers, pi_src_strides, i_src_stride, i_slice_height, p_surface_cache );
+ return;
+ }
+#endif
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
- if(i_plane == 1) i_src_stride /= p_sys->out.i_frame_stride_chroma_div;
+ if(i_plane == 1) i_src_stride /= i_chroma_div;
p_dst = p_pic->p[i_plane].p_pixels;
i_dst_stride = p_pic->p[i_plane].i_pitch;
i_width = p_pic->p[i_plane].i_visible_pitch;
}
}
+int IgnoreOmxDecoderPadding(const char *name)
+{
+ // The list of decoders that signal padding properly is not necessary,
+ // since that is the default, but keep it here for reference. (This is
+ // only relevant for manufacturers that are known to have decoders with
+ // this kind of bug.)
+/*
+ static const char *padding_decoders[] = {
+ "OMX.SEC.AVC.Decoder",
+ "OMX.SEC.wmv7.dec",
+ "OMX.SEC.wmv8.dec",
+ NULL
+ };
+*/
+ static const char *nopadding_decoders[] = {
+ "OMX.SEC.avc.dec",
+ "OMX.SEC.avcdec",
+ "OMX.SEC.MPEG4.Decoder",
+ "OMX.SEC.mpeg4.dec",
+ "OMX.SEC.vc1.dec",
+ NULL
+ };
+ for (const char **ptr = nopadding_decoders; *ptr; ptr++) {
+ if (!strcmp(*ptr, name))
+ return 1;
+ }
+ return 0;
+}
+
/*****************************************************************************
* Logging utility functions
*****************************************************************************/
{
{ VLC_CODEC_MPGV, OMX_VIDEO_CodingMPEG2, "video_decoder.mpeg2" },
{ VLC_CODEC_MP4V, OMX_VIDEO_CodingMPEG4, "video_decoder.mpeg4" },
+ { VLC_CODEC_HEVC, OMX_VIDEO_CodingAutoDetect, "video_decoder.hevc" },
{ VLC_CODEC_H264, OMX_VIDEO_CodingAVC, "video_decoder.avc" },
{ VLC_CODEC_H263, OMX_VIDEO_CodingH263, "video_decoder.h263" },
- { VLC_CODEC_WMV1, OMX_VIDEO_CodingWMV, "video_decoder.wmv" },
- { VLC_CODEC_WMV2, OMX_VIDEO_CodingWMV, "video_decoder.wmv" },
+ { VLC_CODEC_WMV1, OMX_VIDEO_CodingWMV, "video_decoder.wmv1" },
+ { VLC_CODEC_WMV2, OMX_VIDEO_CodingWMV, "video_decoder.wmv2" },
{ VLC_CODEC_WMV3, OMX_VIDEO_CodingWMV, "video_decoder.wmv" },
- { VLC_CODEC_VC1, OMX_VIDEO_CodingWMV, "video_decoder.vc1" },
+ { VLC_CODEC_VC1, OMX_VIDEO_CodingWMV, "video_decoder.wmv" },
{ VLC_CODEC_MJPG, OMX_VIDEO_CodingMJPEG, "video_decoder.jpeg" },
{ VLC_CODEC_MJPG, OMX_VIDEO_CodingMJPEG, "video_decoder.mjpeg" },
{ VLC_CODEC_RV10, OMX_VIDEO_CodingRV, "video_decoder.rv" },
{ VLC_CODEC_RV20, OMX_VIDEO_CodingRV, "video_decoder.rv" },
{ VLC_CODEC_RV30, OMX_VIDEO_CodingRV, "video_decoder.rv" },
{ VLC_CODEC_RV40, OMX_VIDEO_CodingRV, "video_decoder.rv" },
+ { VLC_CODEC_VP8, OMX_VIDEO_CodingAutoDetect, "video_decoder.vp8" },
+ { VLC_CODEC_VP9, OMX_VIDEO_CodingAutoDetect, "video_decoder.vp9" },
{ 0, 0, 0 }
};
} audio_format_table[] =
{
- { VLC_CODEC_AMR_NB, OMX_AUDIO_CodingAMR, "audio_decoder.amr" },
- { VLC_CODEC_AMR_WB, OMX_AUDIO_CodingAMR, "audio_decoder.amr" },
+ { VLC_CODEC_AMR_NB, OMX_AUDIO_CodingAMR, "audio_decoder.amrnb" },
+ { VLC_CODEC_AMR_WB, OMX_AUDIO_CodingAMR, "audio_decoder.amrwb" },
{ VLC_CODEC_MP4A, OMX_AUDIO_CodingAAC, "audio_decoder.aac" },
{ VLC_CODEC_S16N, OMX_AUDIO_CodingPCM, "audio_decoder.pcm" },
+ { VLC_CODEC_MP3, OMX_AUDIO_CodingMP3, "audio_decoder.mp3" },
{ 0, 0, 0 }
};
} audio_enc_format_table[] =
{
- { VLC_CODEC_AMR_NB, OMX_AUDIO_CodingAMR, "audio_encoder.amr" },
- { VLC_CODEC_AMR_WB, OMX_AUDIO_CodingAMR, "audio_encoder.amr" },
+ { VLC_CODEC_AMR_NB, OMX_AUDIO_CodingAMR, "audio_encoder.amrnb" },
+ { VLC_CODEC_AMR_WB, OMX_AUDIO_CodingAMR, "audio_encoder.amrwb" },
{ VLC_CODEC_MP4A, OMX_AUDIO_CodingAAC, "audio_encoder.aac" },
{ VLC_CODEC_S16N, OMX_AUDIO_CodingPCM, "audio_encoder.pcm" },
{ 0, 0, 0 }
{ VLC_CODEC_I420, OMX_COLOR_FormatYUV420PackedPlanar, 3, 1, 2 },
{ VLC_CODEC_NV12, OMX_COLOR_FormatYUV420SemiPlanar, 3, 1, 1 },
{ VLC_CODEC_NV21, OMX_QCOM_COLOR_FormatYVU420SemiPlanar, 3, 1, 1 },
- { VLC_CODEC_NV12, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar, 3, 1, 2 },
+ { VLC_CODEC_NV12, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar, 3, 1, 1 },
{ VLC_CODEC_NV12, QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka, 3, 1, 1 },
+ { VLC_CODEC_NV12, OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m, 3, 1, 1 },
{ VLC_CODEC_YUYV, OMX_COLOR_FormatYCbYCr, 4, 2, 0 },
{ VLC_CODEC_YVYU, OMX_COLOR_FormatYCrYCb, 4, 2, 0 },
{ VLC_CODEC_UYVY, OMX_COLOR_FormatCbYCrY, 4, 2, 0 },
OMX_ERRORTYPE SetAudioParameters(OMX_HANDLETYPE handle,
OmxFormatParam *param, OMX_U32 i_port, OMX_AUDIO_CODINGTYPE encoding,
- uint8_t i_channels, unsigned int i_samplerate, unsigned int i_bitrate,
- unsigned int i_bps, unsigned int i_blocksize)
+ vlc_fourcc_t i_codec, uint8_t i_channels, unsigned int i_samplerate,
+ unsigned int i_bitrate, unsigned int i_bps, unsigned int i_blocksize)
{
OMX_INDEXTYPE index;
OMX_INIT_STRUCTURE(param->amr);
param->amr.nChannels = i_channels;
param->amr.nBitRate = i_bitrate;
- param->amr.eAMRBandMode = OMX_AUDIO_AMRBandModeUnused;
+ if (i_codec == VLC_CODEC_AMR_WB)
+ param->amr.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
+ else
+ param->amr.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
param->amr.eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
- param->amr.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatConformance;
+ param->amr.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
break;
case OMX_AUDIO_CodingG723:
OMX_INIT_STRUCTURE(param->g723);
param->aac.nAACtools = OMX_AUDIO_AACToolAll;
param->aac.nAACERtools = OMX_AUDIO_AACERAll;
param->aac.eAACProfile = OMX_AUDIO_AACObjectLC;
- param->aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatRAW;
- param->aac.eChannelMode = i_channels ?
+ param->aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+ param->aac.eChannelMode = i_channels > 1 ?
OMX_AUDIO_ChannelModeStereo : OMX_AUDIO_ChannelModeMono;
break;
case OMX_AUDIO_CodingMP3:
param->mp3.nChannels = i_channels;
param->mp3.nSampleRate = i_samplerate;
param->mp3.nBitRate = i_bitrate;
- param->mp3.eChannelMode = i_channels ?
+ param->mp3.eChannelMode = i_channels > 1 ?
OMX_AUDIO_ChannelModeStereo : OMX_AUDIO_ChannelModeMono;
param->mp3.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3;
break;
}
/*****************************************************************************
- * PrintOmx: print component summary
+ * PrintOmx: print component summary
*****************************************************************************/
void PrintOmx(decoder_t *p_dec, OMX_HANDLETYPE omx_handle, OMX_U32 i_port)
{
}
}
}
+
+static const struct
+{
+ OMX_VIDEO_AVCPROFILETYPE omx_profile;
+ size_t profile_idc;
+} omx_to_profile_idc[] =
+{
+ { OMX_VIDEO_AVCProfileBaseline, 66 },
+ { OMX_VIDEO_AVCProfileMain, 77 },
+ { OMX_VIDEO_AVCProfileExtended, 88 },
+ { OMX_VIDEO_AVCProfileHigh, 100 },
+ { OMX_VIDEO_AVCProfileHigh10, 110 },
+ { OMX_VIDEO_AVCProfileHigh422, 122 },
+ { OMX_VIDEO_AVCProfileHigh444, 244 },
+};
+
+size_t convert_omx_to_profile_idc(OMX_VIDEO_AVCPROFILETYPE profile_type)
+{
+ size_t array_length = sizeof(omx_to_profile_idc)/sizeof(omx_to_profile_idc[0]);
+ for (size_t i = 0; i < array_length; ++i) {
+ if (omx_to_profile_idc[i].omx_profile == profile_type)
+ return omx_to_profile_idc[i].profile_idc;
+ }
+ return 0;
+}
+
+static const struct
+{
+ OMX_VIDEO_AVCLEVELTYPE omx_level;
+ size_t level_idc;
+} omx_to_level_idc[] =
+{
+ { OMX_VIDEO_AVCLevel1, 10 },
+ { OMX_VIDEO_AVCLevel1b, 9 },
+ { OMX_VIDEO_AVCLevel11, 11 },
+ { OMX_VIDEO_AVCLevel12, 12 },
+ { OMX_VIDEO_AVCLevel13, 13 },
+ { OMX_VIDEO_AVCLevel2, 20 },
+ { OMX_VIDEO_AVCLevel21, 21 },
+ { OMX_VIDEO_AVCLevel22, 22 },
+ { OMX_VIDEO_AVCLevel3, 30 },
+ { OMX_VIDEO_AVCLevel31, 31 },
+ { OMX_VIDEO_AVCLevel32, 32 },
+ { OMX_VIDEO_AVCLevel4, 40 },
+ { OMX_VIDEO_AVCLevel41, 41 },
+ { OMX_VIDEO_AVCLevel42, 42 },
+ { OMX_VIDEO_AVCLevel5, 50 },
+ { OMX_VIDEO_AVCLevel51, 51 },
+};
+
+size_t convert_omx_to_level_idc(OMX_VIDEO_AVCLEVELTYPE level_type)
+{
+ size_t array_length = sizeof(omx_to_level_idc)/sizeof(omx_to_level_idc[0]);
+ for (size_t i = 0; i < array_length; ++i) {
+ if (omx_to_level_idc[i].omx_level == level_type)
+ return omx_to_level_idc[i].level_idc;
+ }
+ return 0;
+}