1 /*****************************************************************************
2 * Copyright (C) 2012-2013 VLC authors and VideoLAN
5 * Nicolas Bertrand <nico@isf.cc>
6 * Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
7 * Jean-Baptiste Kempf <jb@videolan.org>
9 * Valentin Vetter <vvetter@outlook.com>
13 * Pierre Villard <pierre dot villard dot fr at gmail dot com>
19 * This program is free software; you can redistribute it and/or modify it
20 * under the terms of the GNU Lesser General Public License as published by
21 * the Free Software Foundation; either version 2.1 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public License
30 * along with this program; if not, write to the Free Software Foundation,
31 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
32 *****************************************************************************/
36 * @brief DCP access-demux module for Digital Cinema Packages using asdcp library
43 #define KDM_HELP_TEXT "KDM file"
44 #define KDM_HELP_LONG_TEXT "Path to Key Delivery Message XML file"
46 /* VLC core API headers */
47 #include <vlc_common.h>
48 #include <vlc_demux.h>
49 #include <vlc_plugin.h>
63 #include "dcpparser.h"
65 using namespace ASDCP
;
67 #define FRAME_BUFFER_SIZE 1302083 /* maximum frame length, in bytes, after
68 "Digital Cinema System Specification Version 1.2
69 with Errata as of 30 August 2012" */
71 /* Forward declarations */
72 static int Open( vlc_object_t
* );
73 static void Close( vlc_object_t
* );
75 /* Module descriptor */
77 set_shortname( N_( "DCP" ) )
79 add_loadfile( "kdm", "", KDM_HELP_TEXT
, KDM_HELP_LONG_TEXT
, false )
80 set_description( N_( "Digital Cinema Package module" ) )
81 set_capability( "access_demux", 0 )
82 set_category( CAT_INPUT
)
83 set_subcategory( SUBCAT_INPUT_ACCESS
)
84 set_callbacks( Open
, Close
)
87 //! Kind of MXF MEDIA TYPE
88 typedef enum MxfMedia_t
{
96 /* JPEG2000 essence type */
97 ASDCP::JP2K::MXFReader
*p_PicMXFReader
;
99 /* JPEG2000 stereoscopic essence type */
100 ASDCP::JP2K::MXFSReader
*p_PicMXFSReader
;
102 /* MPEG2 essence type */
103 ASDCP::MPEG2::MXFReader
*p_VideoMXFReader
;
108 PCM::MXFReader
*p_AudioMXFReader
;
111 /* ASDCP library (version 1.10.48) can handle files having one of the following Essence Types, as defined in AS_DCP.h:
112 ESS_UNKNOWN, // the file is not a supported AS-DCP essence container
113 ESS_MPEG2_VES, // the file contains an MPEG video elementary stream
114 ESS_JPEG_2000, // the file contains one or more JPEG 2000 codestreams
115 ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs
116 ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs
117 ESS_TIMED_TEXT, // the file contains an XML timed text document and one or more resources
118 ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic).
120 The classes for handling these essence types are defined in AS_DCP.h and are different for each essence type, respectively. The demux_sys_t structure contains members for handling each of these essence types.
126 /* ASDCP Picture Essence Type */
127 EssenceType_t PictureEssType
;
129 /* ASDCP Video MXF Reader */
130 std::vector
<videoReader_t
> v_videoReader
;
132 /* ASDCP Audio MXF Reader */
133 std::vector
<audioReader_t
> v_audioReader
;
135 /* audio buffer size */
136 uint32_t i_audio_buffer
;
138 /* elementary streams */
139 es_out_id_t
*p_video_es
;
140 es_out_id_t
*p_audio_es
;
145 /* current absolute frame number */
150 int frame_rate_denom
;
152 /* total number of frames */
153 uint32_t frames_total
;
155 /* current video reel */
156 unsigned int i_video_reel
;
158 /* current audio reel */
159 unsigned int i_audio_reel
;
161 uint8_t i_chans_to_reorder
; /* do we need channel reordering */
162 uint8_t pi_chan_table
[AOUT_CHAN_MAX
];
168 PictureEssType ( ESS_UNKNOWN
),
177 i_audio_reel( 0 ) {};
181 switch ( PictureEssType
)
186 for ( unsigned int i
= 0; i
< v_videoReader
.size(); i
++ )
188 delete v_videoReader
[i
].p_PicMXFReader
;
191 case ESS_JPEG_2000_S
:
192 for ( unsigned int i
= 0; i
< v_videoReader
.size(); i
++ )
194 delete v_videoReader
[i
].p_PicMXFSReader
;
198 for ( unsigned int i
= 0; i
< v_videoReader
.size(); i
++ )
200 delete v_videoReader
[i
].p_VideoMXFReader
;
207 for ( unsigned int i
= 0; i
< v_audioReader
.size(); i
++ )
209 delete v_audioReader
[i
].p_AudioMXFReader
;
216 /*TODO: basic correlation between SMPTE S428-3/S429-2
217 * Real sound is more complex with case of left/right surround, ...
218 * and hearing impaired/Narration channels */
220 /* 1 channel: mono */
221 static const uint32_t i_channels_1
[] =
222 { AOUT_CHAN_LEFT
, 0 };
224 /* 2 channels: stereo */
225 static const uint32_t i_channels_2
[]=
226 { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
, 0 };
229 static const uint32_t i_channels_4
[] =
230 { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
, AOUT_CHAN_CENTER
,
233 /* 6 channels: 5.1 */
234 static const uint32_t i_channels_6
[] =
235 { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
, AOUT_CHAN_CENTER
,
236 AOUT_CHAN_LFE
, AOUT_CHAN_REARLEFT
, AOUT_CHAN_REARRIGHT
,
239 /* 7 channels: 6.1 */
240 static const uint32_t i_channels_7
[] =
241 { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
, AOUT_CHAN_CENTER
,
242 AOUT_CHAN_LFE
, AOUT_CHAN_REARLEFT
, AOUT_CHAN_REARRIGHT
,
243 AOUT_CHAN_REARCENTER
, 0 };
245 /* 8 channels: 7.1 */
246 static const uint32_t i_channels_8
[] =
247 { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
, AOUT_CHAN_CENTER
,
248 AOUT_CHAN_LFE
, AOUT_CHAN_REARLEFT
, AOUT_CHAN_REARRIGHT
,
249 AOUT_CHAN_MIDDLELEFT
, AOUT_CHAN_MIDDLERIGHT
, 0 };
251 /* 9 channels; 8.1 */
252 static const uint32_t i_channels_9
[] =
253 { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
, AOUT_CHAN_CENTER
,
254 AOUT_CHAN_LFE
, AOUT_CHAN_REARLEFT
, AOUT_CHAN_REARRIGHT
,
255 AOUT_CHAN_MIDDLELEFT
, AOUT_CHAN_MIDDLERIGHT
, AOUT_CHAN_REARCENTER
, 0 };
257 static const uint32_t *pi_channels_aout
[] =
269 static const unsigned i_channel_mask
[] =
277 AOUT_CHANS_6_1_MIDDLE
,
281 /*****************************************************************************
283 *****************************************************************************/
285 static int Demux( demux_t
* );
286 static int Control( demux_t
*, int, va_list );
288 int dcpInit ( demux_t
*p_demux
);
289 int parseXML ( demux_t
* p_demux
);
290 static inline void fillVideoFmt(
291 video_format_t
* fmt
, unsigned int width
, unsigned int height
,
292 unsigned int frame_rate_num
, unsigned int frame_rate_denom
);
293 void CloseDcpAndMxf( demux_t
*p_demux
);
297 /*****************************************************************************
298 * Open: module init function
299 *****************************************************************************/
300 static int Open( vlc_object_t
*obj
)
302 demux_t
*p_demux
= ( demux_t
* ) obj
;
304 es_format_t video_format
, audio_format
;
307 if( !p_demux
->psz_file
)
310 p_sys
= new ( nothrow
) demux_sys_t();
311 if( unlikely( p_sys
== NULL
) ) {
314 p_demux
->p_sys
= p_sys
;
316 /* Allocate DCP object */
317 dcp_t
*p_dcp
= new ( nothrow
) dcp_t
;
318 if( unlikely( p_dcp
== NULL
) ) {
322 p_sys
->p_dcp
= p_dcp
;
325 /* handle the DCP directory, saving the paths for audio and video file, returning error if unsuccessful */
326 if( ( retval
= dcpInit( p_demux
) ) )
329 /* Open video file */
330 EssenceType_t essInter
;
331 for ( size_t i
= 0; i
< ( p_sys
->p_dcp
->video_reels
.size() ); i
++ )
333 EssenceType( p_sys
->p_dcp
->video_reels
[i
].filename
.c_str(), essInter
);
336 p_sys
->PictureEssType
= essInter
;
340 if ( essInter
!= p_sys
->PictureEssType
)
342 msg_Err( p_demux
, "Integrity check failed : different essence containers" );
343 retval
= VLC_EGENERIC
;
351 msg_Err( p_demux
, "The file %s is not a supported AS_DCP essence container", p_sys
->p_dcp
->video_reels
[i
].filename
.c_str() );
352 retval
= VLC_EGENERIC
;
356 case ESS_JPEG_2000_S
: {
357 JP2K::PictureDescriptor PicDesc
;
358 if (p_sys
->PictureEssType
== ESS_JPEG_2000_S
) { /* 3D JPEG2000 */
359 JP2K::MXFSReader
* p_PicMXFSReader
= new ( nothrow
) JP2K::MXFSReader();
361 if( !p_PicMXFSReader
) {
365 if( !ASDCP_SUCCESS( p_PicMXFSReader
->OpenRead( p_sys
->p_dcp
->video_reels
[i
].filename
.c_str() ) ) ) {
366 msg_Err( p_demux
, "File %s could not be opened with ASDCP", p_sys
->p_dcp
->video_reels
[i
].filename
.c_str() );
367 retval
= VLC_EGENERIC
;
368 delete p_PicMXFSReader
;
372 p_PicMXFSReader
->FillPictureDescriptor( PicDesc
);
373 videoReader_t videoReader
;
374 videoReader
.p_PicMXFSReader
= p_PicMXFSReader
;
375 p_sys
->v_videoReader
.push_back(videoReader
);
376 } else { /* 2D JPEG2000 */
377 JP2K::MXFReader
*p_PicMXFReader
= new ( nothrow
) JP2K::MXFReader();
378 if( !p_PicMXFReader
) {
382 if( !ASDCP_SUCCESS( p_PicMXFReader
->OpenRead( p_sys
->p_dcp
->video_reels
[i
].filename
.c_str() ) ) ) {
383 msg_Err( p_demux
, "File %s could not be opened with ASDCP",
384 p_sys
->p_dcp
->video_reels
[i
].filename
.c_str() );
385 retval
= VLC_EGENERIC
;
386 delete p_PicMXFReader
;
390 p_PicMXFReader
->FillPictureDescriptor( PicDesc
);
391 videoReader_t videoReader
;
392 videoReader
.p_PicMXFReader
= p_PicMXFReader
;
393 p_sys
->v_videoReader
.push_back(videoReader
);
395 es_format_Init( &video_format
, VIDEO_ES
, VLC_CODEC_JPEG2000
);
396 fillVideoFmt( &video_format
.video
, PicDesc
.StoredWidth
, PicDesc
.StoredHeight
,
397 PicDesc
.EditRate
.Numerator
, PicDesc
.EditRate
.Denominator
);
401 if ( p_sys
->frame_rate_num
!= PicDesc
.EditRate
.Numerator
||
402 p_sys
->frame_rate_denom
!= PicDesc
.EditRate
.Denominator
)
404 msg_Err( p_demux
, "Integrity check failed : different frame rates" );
405 retval
= VLC_EGENERIC
;
411 p_sys
->frame_rate_num
= PicDesc
.EditRate
.Numerator
;
412 p_sys
->frame_rate_denom
= PicDesc
.EditRate
.Denominator
;
415 p_sys
->frames_total
+= p_sys
->p_dcp
->video_reels
[i
].i_duration
;
418 case ESS_MPEG2_VES
: {
420 MPEG2::MXFReader
*p_VideoMXFReader
= new ( nothrow
) MPEG2::MXFReader();
422 videoReader_t videoReader
;
423 videoReader
.p_VideoMXFReader
= p_VideoMXFReader
;
424 p_sys
->v_videoReader
.push_back(videoReader
);
426 MPEG2::VideoDescriptor VideoDesc
;
428 if( !p_VideoMXFReader
) {
433 if( !ASDCP_SUCCESS( p_VideoMXFReader
->OpenRead( p_sys
->p_dcp
->video_reels
[i
].filename
.c_str() ) ) ) {
434 msg_Err( p_demux
, "File %s could not be opened with ASDCP", p_sys
->p_dcp
->video_reels
[i
].filename
.c_str() );
435 retval
= VLC_EGENERIC
;
439 p_VideoMXFReader
->FillVideoDescriptor( VideoDesc
);
441 es_format_Init( &video_format
, VIDEO_ES
, VLC_CODEC_MPGV
);
442 fillVideoFmt( &video_format
.video
, VideoDesc
.StoredWidth
, VideoDesc
.StoredHeight
,
443 VideoDesc
.EditRate
.Numerator
, VideoDesc
.EditRate
.Denominator
);
447 if ( p_sys
->frame_rate_num
!= VideoDesc
.EditRate
.Numerator
||
448 p_sys
->frame_rate_denom
!= VideoDesc
.EditRate
.Denominator
)
450 msg_Err( p_demux
, "Integrity check failed : different frame rates" );
451 retval
= VLC_EGENERIC
;
457 p_sys
->frame_rate_num
= VideoDesc
.EditRate
.Numerator
;
458 p_sys
->frame_rate_denom
= VideoDesc
.EditRate
.Denominator
;
461 p_sys
->frames_total
+= p_sys
->p_dcp
->video_reels
[i
].i_duration
;
465 msg_Err( p_demux
, "Unrecognized video format" );
466 retval
= VLC_EGENERIC
;
471 if ( (p_sys
->frame_rate_num
== 0) || (p_sys
->frame_rate_denom
== 0) ) {
472 msg_Err(p_demux
, "Invalid frame rate (%i/%i)",
473 p_sys
->frame_rate_num
, p_sys
->frame_rate_denom
);
474 retval
= VLC_EGENERIC
;
478 if( ( p_sys
->p_video_es
= es_out_Add( p_demux
->out
, &video_format
) ) == NULL
) {
479 msg_Err( p_demux
, "Failed to add video es" );
480 retval
= VLC_EGENERIC
;
484 /* Open audio file */
485 EssenceType_t AudioEssType
;
486 EssenceType_t AudioEssTypeCompare
;
488 if( !p_sys
->p_dcp
->audio_reels
.empty() )
490 EssenceType( p_sys
->p_dcp
->audio_reels
[0].filename
.c_str(), AudioEssType
);
492 if ( (AudioEssType
== ESS_PCM_24b_48k
) || (AudioEssType
== ESS_PCM_24b_96k
) ) {
493 PCM::AudioDescriptor AudioDesc
;
495 for ( size_t i
= 0; i
< ( p_sys
->p_dcp
->audio_reels
.size() ); i
++)
499 EssenceType( p_sys
->p_dcp
->audio_reels
[i
].filename
.c_str(), AudioEssTypeCompare
);
500 if ( AudioEssTypeCompare
!= AudioEssType
)
502 msg_Err( p_demux
, "Integrity check failed : different audio essence types in %s",
503 p_sys
->p_dcp
->audio_reels
[i
].filename
.c_str() );
504 retval
= VLC_EGENERIC
;
508 PCM::MXFReader
*p_AudioMXFReader
= new ( nothrow
) PCM::MXFReader();
510 if( !p_AudioMXFReader
) {
515 if( !ASDCP_SUCCESS( p_AudioMXFReader
->OpenRead( p_sys
->p_dcp
->audio_reels
[i
].filename
.c_str() ) ) ) {
516 msg_Err( p_demux
, "File %s could not be opened with ASDCP",
517 p_sys
->p_dcp
->audio_reels
[i
].filename
.c_str() );
518 retval
= VLC_EGENERIC
;
519 delete p_AudioMXFReader
;
523 p_AudioMXFReader
->FillAudioDescriptor( AudioDesc
);
525 if ( (AudioDesc
.ChannelCount
>= sizeof(pi_channels_aout
)/sizeof(uint32_t *))
526 || (pi_channels_aout
[AudioDesc
.ChannelCount
] == NULL
) )
528 msg_Err(p_demux
, " DCP module does not support %i channels", AudioDesc
.ChannelCount
);
529 retval
= VLC_EGENERIC
;
530 delete p_AudioMXFReader
;
533 audioReader_t audioReader
;
534 audioReader
.p_AudioMXFReader
= p_AudioMXFReader
;
535 p_sys
->v_audioReader
.push_back( audioReader
);
538 es_format_Init( &audio_format
, AUDIO_ES
, VLC_CODEC_S24L
);
539 if( AudioDesc
.AudioSamplingRate
.Denominator
!= 0 )
540 audio_format
.audio
.i_rate
=
541 AudioDesc
.AudioSamplingRate
.Numerator
542 / AudioDesc
.AudioSamplingRate
.Denominator
;
543 else if ( AudioEssType
== ESS_PCM_24b_96k
)
544 audio_format
.audio
.i_rate
= 96000;
546 audio_format
.audio
.i_rate
= 48000;
548 p_sys
->i_audio_buffer
= PCM::CalcFrameBufferSize( AudioDesc
);
549 if (p_sys
->i_audio_buffer
== 0) {
550 msg_Err( p_demux
, "Failed to get audio buffer size" );
551 retval
= VLC_EGENERIC
;
555 audio_format
.audio
.i_bitspersample
= AudioDesc
.QuantizationBits
;
556 audio_format
.audio
.i_blockalign
= AudioDesc
.BlockAlign
;
557 audio_format
.audio
.i_channels
=
558 p_sys
->i_channels
= AudioDesc
.ChannelCount
;
560 /* Manage channel orders */
561 p_sys
->i_chans_to_reorder
= aout_CheckChannelReorder(
562 pi_channels_aout
[AudioDesc
.ChannelCount
], NULL
,
563 i_channel_mask
[AudioDesc
.ChannelCount
], p_sys
->pi_chan_table
);
565 if( ( p_sys
->p_audio_es
= es_out_Add( p_demux
->out
, &audio_format
) ) == NULL
) {
566 msg_Err( p_demux
, "Failed to add audio es" );
567 retval
= VLC_EGENERIC
;
571 msg_Err( p_demux
, "The file %s is not a supported AS_DCP essence container",
572 p_sys
->p_dcp
->audio_reels
[0].filename
.c_str() );
573 retval
= VLC_EGENERIC
;
577 p_demux
->pf_demux
= Demux
;
578 p_demux
->pf_control
= Control
;
579 p_sys
->frame_no
= p_sys
->p_dcp
->video_reels
[0].i_entrypoint
;
583 CloseDcpAndMxf( p_demux
);
588 /*****************************************************************************
589 * Close: module destroy function
590 *****************************************************************************/
591 static inline void Close( vlc_object_t
*obj
)
593 demux_t
*p_demux
= ( demux_t
* ) obj
;
594 CloseDcpAndMxf( p_demux
);
599 /*****************************************************************************
600 * Demux: DCP Demuxing function
601 *****************************************************************************/
602 static int Demux( demux_t
*p_demux
)
604 demux_sys_t
*p_sys
= p_demux
->p_sys
;
605 block_t
*p_video_frame
= NULL
, *p_audio_frame
= NULL
;
607 PCM::FrameBuffer
AudioFrameBuff( p_sys
->i_audio_buffer
);
608 AESDecContext video_aes_ctx
, audio_aes_ctx
;
610 /* swaping video reels */
611 if ( p_sys
->frame_no
== p_sys
->p_dcp
->video_reels
[p_sys
->i_video_reel
].i_absolute_end
)
613 if ( p_sys
->i_video_reel
+ 1 == p_sys
->v_videoReader
.size() )
619 p_sys
->i_video_reel
++;
623 /* swaping audio reels */
624 if ( !p_sys
->p_dcp
->audio_reels
.empty() && p_sys
->frame_no
== p_sys
->p_dcp
->audio_reels
[p_sys
->i_audio_reel
].i_absolute_end
)
626 if ( p_sys
->i_audio_reel
+ 1 == p_sys
->v_audioReader
.size() )
628 return 0;//should never go there
632 p_sys
->i_audio_reel
++;
638 /* initialize AES context, if reel is encrypted */
641 p_sys
->p_dcp
->video_reels
.size() > p_sys
->i_video_reel
&&
642 p_sys
->p_dcp
->video_reels
[p_sys
->i_video_reel
].p_key
)
644 if( ! ASDCP_SUCCESS( video_aes_ctx
.InitKey( p_sys
->p_dcp
->video_reels
[p_sys
->i_video_reel
].p_key
->getKey() ) ) )
646 msg_Err( p_demux
, "ASDCP failed to initialize AES key" );
651 switch( p_sys
->PictureEssType
)
654 case ESS_JPEG_2000_S
:{
655 JP2K::FrameBuffer
PicFrameBuff(FRAME_BUFFER_SIZE
);
656 int nextFrame
= p_sys
->frame_no
+ p_sys
->p_dcp
->video_reels
[p_sys
->i_video_reel
].i_correction
;
657 if ( ( p_video_frame
= block_Alloc( FRAME_BUFFER_SIZE
)) == NULL
)
660 if ( ! ASDCP_SUCCESS(
661 PicFrameBuff
.SetData(p_video_frame
->p_buffer
, FRAME_BUFFER_SIZE
)) )
663 if ( p_sys
->PictureEssType
== ESS_JPEG_2000_S
) {
664 if ( ! ASDCP_SUCCESS(
665 p_sys
->v_videoReader
[p_sys
->i_video_reel
].p_PicMXFSReader
->ReadFrame(nextFrame
, JP2K::SP_LEFT
, PicFrameBuff
, &video_aes_ctx
, 0)) ) {
666 PicFrameBuff
.SetData(0,0);
670 if ( ! ASDCP_SUCCESS(
671 p_sys
->v_videoReader
[p_sys
->i_video_reel
].p_PicMXFReader
->ReadFrame(nextFrame
, PicFrameBuff
, &video_aes_ctx
, 0)) ) {
672 PicFrameBuff
.SetData(0,0);
676 p_video_frame
->i_buffer
= PicFrameBuff
.Size();
679 case ESS_MPEG2_VES
: {
680 MPEG2::FrameBuffer
VideoFrameBuff(FRAME_BUFFER_SIZE
);
681 if ( ( p_video_frame
= block_Alloc( FRAME_BUFFER_SIZE
)) == NULL
)
684 if ( ! ASDCP_SUCCESS(
685 VideoFrameBuff
.SetData(p_video_frame
->p_buffer
, FRAME_BUFFER_SIZE
)) )
688 if ( ! ASDCP_SUCCESS(
689 p_sys
->v_videoReader
[p_sys
->i_video_reel
].p_VideoMXFReader
->ReadFrame(p_sys
->frame_no
+ p_sys
->p_dcp
->video_reels
[p_sys
->i_video_reel
].i_correction
, VideoFrameBuff
, &video_aes_ctx
, 0)) ) {
690 VideoFrameBuff
.SetData(0,0);
694 p_video_frame
->i_buffer
= VideoFrameBuff
.Size();
698 msg_Err( p_demux
, "Unrecognized video format" );
702 p_video_frame
->i_length
= CLOCK_FREQ
* p_sys
->frame_rate_denom
/ p_sys
->frame_rate_num
;
703 p_video_frame
->i_pts
= CLOCK_FREQ
* p_sys
->frame_no
* p_sys
->frame_rate_denom
/ p_sys
->frame_rate_num
;
705 if( !p_sys
->p_dcp
->audio_reels
.empty() )
708 if ( ( p_audio_frame
= block_Alloc( p_sys
->i_audio_buffer
)) == NULL
) {
712 /* initialize AES context, if reel is encrypted */
715 p_sys
->p_dcp
->audio_reels
.size() > p_sys
->i_audio_reel
&&
716 p_sys
->p_dcp
->audio_reels
[p_sys
->i_audio_reel
].p_key
)
718 if( ! ASDCP_SUCCESS( audio_aes_ctx
.InitKey( p_sys
->p_dcp
->audio_reels
[p_sys
->i_audio_reel
].p_key
->getKey() ) ) )
720 msg_Err( p_demux
, "ASDCP failed to initialize AES key" );
725 if ( ! ASDCP_SUCCESS(
726 AudioFrameBuff
.SetData(p_audio_frame
->p_buffer
, p_sys
->i_audio_buffer
)) ) {
730 if ( ! ASDCP_SUCCESS(
731 p_sys
->v_audioReader
[p_sys
->i_audio_reel
].p_AudioMXFReader
->ReadFrame(p_sys
->frame_no
+ p_sys
->p_dcp
->audio_reels
[p_sys
->i_audio_reel
].i_correction
, AudioFrameBuff
, &audio_aes_ctx
, 0)) ) {
732 AudioFrameBuff
.SetData(0,0);
736 if( p_sys
->i_chans_to_reorder
)
737 aout_ChannelReorder( p_audio_frame
->p_buffer
, p_audio_frame
->i_buffer
,
739 p_sys
->pi_chan_table
, VLC_CODEC_S24L
);
741 p_audio_frame
->i_buffer
= AudioFrameBuff
.Size();
742 p_audio_frame
->i_length
= CLOCK_FREQ
* p_sys
->frame_rate_denom
/ p_sys
->frame_rate_num
;
743 p_audio_frame
->i_pts
= CLOCK_FREQ
* p_sys
->frame_no
* p_sys
->frame_rate_denom
/ p_sys
->frame_rate_num
;
744 /* Video is the main pts */
745 if ( p_audio_frame
->i_pts
!= p_video_frame
->i_pts
) {
746 msg_Err( p_demux
, "Audio and video frame pts are not in sync" );
750 p_sys
->i_pts
= p_video_frame
->i_pts
;
751 es_out_Control( p_demux
->out
, ES_OUT_SET_PCR
, p_sys
->i_pts
);
753 es_out_Send( p_demux
->out
, p_sys
->p_video_es
, p_video_frame
);
755 es_out_Send( p_demux
->out
, p_sys
->p_audio_es
, p_audio_frame
);
762 msg_Err( p_demux
, "Couldn't read frame with ASDCP");
765 block_Release(p_video_frame
);
767 block_Release(p_audio_frame
);
771 /*****************************************************************************
772 * Control: handle the controls
773 *****************************************************************************/
774 static int Control( demux_t
*p_demux
, int query
, va_list args
)
779 demux_sys_t
*p_sys
= p_demux
->p_sys
;
783 case DEMUX_CAN_PAUSE
:
784 case DEMUX_CAN_CONTROL_PACE
:
785 pb
= va_arg ( args
, bool* );
790 pb
= va_arg( args
, bool * );
791 if( p_sys
->PictureEssType
!= ESS_MPEG2_VES
)
797 case DEMUX_SET_PAUSE_STATE
:
800 case DEMUX_GET_POSITION
:
801 pf
= va_arg( args
, double * );
802 if( p_sys
->frames_total
!= 0 )
803 *pf
= (double) p_sys
->frame_no
/ (double) p_sys
->frames_total
;
805 msg_Warn( p_demux
, "Total number of frames is 0" );
810 case DEMUX_SET_POSITION
:
811 f
= va_arg( args
, double );
812 p_sys
->frame_no
= (int) ( f
* p_sys
->frames_total
);
815 case DEMUX_GET_LENGTH
:
816 pi64
= va_arg ( args
, int64_t * );
817 *pi64
= ( p_sys
->frames_total
* p_sys
->frame_rate_denom
/ p_sys
->frame_rate_num
) * CLOCK_FREQ
;
821 pi64
= va_arg( args
, int64_t * );
822 *pi64
= p_sys
->i_pts
>= 0 ? p_sys
->i_pts
: 0;
826 i64
= va_arg( args
, int64_t );
827 msg_Warn( p_demux
, "DEMUX_SET_TIME" );
828 p_sys
->frame_no
= i64
* p_sys
->frame_rate_num
/ ( CLOCK_FREQ
* p_sys
->frame_rate_denom
);
830 es_out_Control( p_demux
->out
, ES_OUT_SET_PCR
, p_sys
->i_pts
);
831 es_out_Control( p_demux
->out
, ES_OUT_SET_NEXT_DISPLAY_TIME
, ( mtime_t
) i64
);
833 case DEMUX_GET_PTS_DELAY
:
834 pi64
= va_arg( args
, int64_t * );
836 INT64_C(1000) * var_InheritInteger( p_demux
, "file-caching" );
841 msg_Warn( p_demux
, "Unknown query %d in DCP Control", query
);
849 /*****************************************************************************
850 * Low-level functions : string manipulation, free function, etc
851 *****************************************************************************/
853 * Function to fill video_format_t fields for an elementary stream
854 * @param fmt video format structure
855 * @param width picture width
856 * @param height picture height
857 * @param frame_rate_num video frame rate numerator
858 * @param frame_rate_denom video frame rate denominator
860 static inline void fillVideoFmt( video_format_t
* fmt
, unsigned int width
, unsigned int height
, unsigned int frame_rate_num
, unsigned int frame_rate_denom
)
862 fmt
->i_width
= width
;
863 fmt
->i_height
= height
;
864 /* As input are square pixels let VLC or decoder fix SAR, origin,
865 * and visible area */
866 fmt
->i_frame_rate
= frame_rate_num
;
867 fmt
->i_frame_rate_base
= frame_rate_denom
;
871 * Function to free memory in case of error or when closing the module
872 * @param p_demux DCP access-demux
876 void CloseDcpAndMxf( demux_t
*p_demux
)
878 demux_sys_t
*p_sys
= p_demux
->p_sys
;
879 /* close the files */
880 switch( p_sys
->PictureEssType
)
885 for ( size_t i
= 0; i
< p_sys
->v_videoReader
.size(); i
++ )
887 if( p_sys
->v_videoReader
[i
].p_PicMXFReader
)
888 p_sys
->v_videoReader
[i
].p_PicMXFReader
->Close();
891 case ESS_JPEG_2000_S
:
892 for ( size_t i
= 0; i
< p_sys
->v_videoReader
.size(); i
++ )
894 if( p_sys
->v_videoReader
[i
].p_PicMXFSReader
)
895 p_sys
->v_videoReader
[i
].p_PicMXFSReader
->Close();
899 for ( size_t i
= 0; i
< p_sys
->v_videoReader
.size(); i
++ )
901 if( p_sys
->v_videoReader
[i
].p_VideoMXFReader
)
902 p_sys
->v_videoReader
[i
].p_VideoMXFReader
->Close();
909 for ( size_t i
= 0; i
< p_sys
->v_audioReader
.size(); i
++ )
911 if( p_sys
->v_audioReader
[i
].p_AudioMXFReader
)
912 p_sys
->v_audioReader
[i
].p_AudioMXFReader
->Close();
915 delete( p_demux
->p_sys
);
919 /*****************************************************************************
921 *****************************************************************************/
924 * Function to handle the operations with the DCP directory.
925 * @param p_demux Demux pointer.
926 * @return Integer according to the success or not of the process.
928 int dcpInit ( demux_t
*p_demux
)
932 demux_sys_t
*p_sys
= p_demux
->p_sys
;
933 dcp_t
*p_dcp
= p_sys
->p_dcp
;
935 p_dcp
->path
= p_demux
->psz_file
;
936 /* Add a '/' in end of path if needed */
937 if ( *(p_dcp
->path
).rbegin() != '/')
938 p_dcp
->path
.append( "/" );
940 /* Parsing XML files to get audio and video files */
941 msg_Dbg( p_demux
, "parsing XML files..." );
942 if( ( retval
= parseXML( p_demux
) ) )
945 msg_Dbg(p_demux
, "parsing XML files done");
951 /*****************************************************************************
952 * functions for XML parsing
953 *****************************************************************************/
956 * Function to retrieve the path to the ASSETMAP file.
957 * @param p_demux DCP access_demux.
959 static std::string
assetmapPath( demux_t
* p_demux
)
962 struct dirent
*ent
= NULL
;
963 dcp_t
*p_dcp
= p_demux
->p_sys
->p_dcp
;
966 if( ( dir
= opendir (p_dcp
->path
.c_str() ) ) != NULL
)
968 /* print all the files and directories within directory */
969 while( ( ent
= readdir ( dir
) ) != NULL
)
971 if( strcasecmp( "assetmap", ent
->d_name
) == 0 || strcasecmp( "assetmap.xml", ent
->d_name
) == 0 )
973 /* copy of "path" in "res" */
974 result
= p_dcp
->path
;
975 result
.append( ent
->d_name
);
982 msg_Err( p_demux
, "Could not open the directory: %s", p_dcp
->path
.c_str() );
984 /* if no assetmap file */
986 msg_Err( p_demux
, "No ASSETMAP found in the directory: %s", p_dcp
->path
.c_str() );
993 * Function which parses XML files in DCP directory in order to get video and audio files
994 * @param p_demux Demux pointer.
995 * @return Integer according to the success or not of the operation
997 int parseXML ( demux_t
* p_demux
)
1001 std::string assetmap_path
= assetmapPath( p_demux
);
1002 /* We get the ASSETMAP file path */
1003 if( assetmap_path
.empty() )
1004 return VLC_EGENERIC
;
1006 /* We parse the ASSETMAP File in order to get CPL File path, PKL File path
1007 and to store UID/Path of all files in DCP directory (except ASSETMAP file) */
1008 AssetMap
*assetmap
= new (nothrow
) AssetMap( p_demux
, assetmap_path
, p_demux
->p_sys
->p_dcp
);
1009 if( ( retval
= assetmap
->Parse() ) )
1013 return VLC_SUCCESS
; /* TODO : perform checking on XML parsing */