
Recherche avancée
Médias (1)
-
The Slip - Artworks
26 septembre 2011, par
Mis à jour : Septembre 2011
Langue : English
Type : Texte
Autres articles (64)
-
Publier sur MédiaSpip
13 juin 2013Puis-je poster des contenus à partir d’une tablette Ipad ?
Oui, si votre Médiaspip installé est à la version 0.2 ou supérieure. Contacter au besoin l’administrateur de votre MédiaSpip pour le savoir -
Ajouter notes et légendes aux images
7 février 2011, parPour pouvoir ajouter notes et légendes aux images, la première étape est d’installer le plugin "Légendes".
Une fois le plugin activé, vous pouvez le configurer dans l’espace de configuration afin de modifier les droits de création / modification et de suppression des notes. Par défaut seuls les administrateurs du site peuvent ajouter des notes aux images.
Modification lors de l’ajout d’un média
Lors de l’ajout d’un média de type "image" un nouveau bouton apparait au dessus de la prévisualisation (...) -
MediaSPIP 0.1 Beta version
25 avril 2011, parMediaSPIP 0.1 beta is the first version of MediaSPIP proclaimed as "usable".
The zip file provided here only contains the sources of MediaSPIP in its standalone version.
To get a working installation, you must manually install all-software dependencies on the server.
If you want to use this archive for an installation in "farm mode", you will also need to proceed to other manual (...)
Sur d’autres sites (9129)
-
My journey to Coviu
27 octobre 2015, par silviaMy new startup just released our MVP – this is the story of what got me here.
I love creating new applications that let people do their work better or in a manner that wasn’t possible before.
My first such passion was as a student intern when I built a system for a building and loan association’s monthly customer magazine. The group I worked with was managing their advertiser contacts through a set of paper cards and I wrote a dBase based system (yes, that long ago) that would manage their customer relationships. They loved it – until it got replaced by an SAP system that cost 100 times what I cost them, had really poor UX, and only gave them half the functionality. It was a corporate system with ongoing support, which made all the difference to them.
The story repeated itself with a CRM for my Uncle’s construction company, and with a resume and quotation management system for Accenture right after Uni, both of which I left behind when I decided to go into research.
Even as a PhD student, I never lost sight of challenges that people were facing and wanted to develop technology to overcome problems. The aim of my PhD thesis was to prepare for the oncoming onslaught of audio and video on the Internet (yes, this was 1994 !) by developing algorithms to automatically extract and locate information in such files, which would enable users to structure, index and search such content.
Many of the use cases that we explored are now part of products or continue to be challenges : finding music that matches your preferences, identifying music or video pieces e.g. to count ads on the radio or to mark copyright infringement, or the automated creation of video summaries such as trailers.
This continued when I joined the CSIRO in Australia – I was working on segmenting speech into words or talk spurts since that would simplify captioning & subtitling, and on MPEG-7 which was a (slightly over-engineered) standard to structure metadata about audio and video.
In 2001 I had the idea of replicating the Web for videos : i.e. creating hyperlinked and searchable video-only experiences. We called it “Annodex” for annotated and indexed video and it needed full-screen hyperlinked video in browsers – man were we ahead of our time ! It was my first step into standards, got several IETF RFCs to my name, and started my involvement with open codecs through Xiph.
Around the time that YouTube was founded in 2006, I founded Vquence – originally a video search company for the Web, but pivoted to a video metadata mining company. Vquence still exists and continues to sell its data to channel partners, but it lacks the user impact that has always driven my work.
As the video element started being developed for HTML5, I had to get involved. I contributed many use cases to the W3C, became a co-editor of the HTML5 spec and focused on video captioning with WebVTT while contracting to Mozilla and later to Google. We made huge progress and today the technology exists to publish video on the Web with captions, making the Web more inclusive for everybody. I contributed code to YouTube and Google Chrome, but was keen to make a bigger impact again.
The opportunity came when a couple of former CSIRO colleagues who now worked for NICTA approached me to get me interested in addressing new use cases for video conferencing in the context of WebRTC. We worked on a kiosk-style solution to service delivery for large service organisations, particularly targeting government. The emerging WebRTC standard posed many technical challenges that we addressed by building rtc.io , by contributing to the standards, and registering bugs on the browsers.
Fast-forward through the development of a few further custom solutions for customers in health and education and we are starting to see patterns of need emerge. The core learning that we’ve come away with is that to get things done, you have to go beyond “talking heads” in a video call. It’s not just about seeing the other person, but much more about having a shared view of the things that need to be worked on and a shared way of interacting with them. Also, we learnt that the things that are being worked on are quite varied and may include multiple input cameras, digital documents, Web pages, applications, device data, controls, forms.
So we set out to build a solution that would enable productive remote collaboration to take place. It would need to provide an excellent user experience, it would need to be simple to work with, provide for the standard use cases out of the box, yet be architected to be extensible for specialised data sharing needs that we knew some of our customers had. It would need to be usable directly on Coviu.com, but also able to integrate with specialised applications that some of our customers were already using, such as the applications that they spend most of their time in (CRMs, practice management systems, learning management systems, team chat systems). It would need to require our customers to sign up, yet their clients to join a call without sign-up.
Collaboration is a big problem. People are continuing to get more comfortable with technology and are less and less inclined to travel distances just to get a service done. In a country as large as Australia, where 12% of the population lives in rural and remote areas, people may not even be able to travel distances, particularly to receive or provide recurring or specialised services, or to achieve work/life balance. To make the world a global village, we need to be able to work together better remotely.
The need for collaboration is being recognised by specialised Web applications already, such as the LiveShare feature of Invision for Designers, Codassium for pair programming, or the recently announced Dropbox Paper. Few go all the way to video – WebRTC is still regarded as a complicated feature to support.
With Coviu, we’d like to offer a collaboration feature to every Web app. We now have a Web app that provides a modern and beautifully designed collaboration interface. To enable other Web apps to integrate it, we are now developing an API. Integration may entail customisation of the data sharing part of Coviu – something Coviu has been designed for. How to replicate the data and keep it consistent when people collaborate remotely – that is where Coviu makes a difference.
We have started our journey and have just launched free signup to the Coviu base product, which allows individuals to own their own “room” (i.e. a fixed URL) in which to collaborate with others. A huge shout out goes to everyone in the Coviu team – a pretty amazing group of people – who have turned the app from an idea to reality. You are all awesome !
With Coviu you can share and annotate :
- images (show your mum photos of your last holidays, or get feedback on an architecture diagram from a customer),
- pdf files (give a presentation remotely, or walk a customer through a contract),
- whiteboards (brainstorm with a colleague), and
- share an application window (watch a YouTube video together, or work through your task list with your colleagues).
All of these are regarded as “shared documents” in Coviu and thus have zooming and annotations features and are listed in a document tray for ease of navigation.
This is just the beginning of how we want to make working together online more productive. Give it a go and let us know what you think.
The post My journey to Coviu first appeared on ginger’s thoughts.
-
H.264 muxing to MP4 from CCTV (HW) encoder using ffmpeg library in C / C++, how to fetch AVCodecContext::extradata
26 mai 2016, par DomI am trying to mux a video to mp4 file from packets received via SDK API of CCTV camera. The stream from CCTV seems to consist of packets of h264 I and P-frames only (no B-frames).
The problem is, that the file is not playable in Daum PotPlayer when I leave the AVCodecContext::extradata empty, however, I can play the file in VLC. If I feed the extra data (probably not correctly - I just copy the first 50 bytes from the packet received from the HW encoder), the file is playable in PotPlayer, but not in VLC.
I do not know, how to prepare the extradata properly.
The code below shows the muxing.
void WriteVideo()
{
AVFormatContext* formatContext = nullptr;
AVStream* stream = nullptr;
int ret = 0;
ret = avformat_alloc_output_context2(&formatContext, nullptr, "mp4", OUTPUT_V_FILE_NAME);
if (ret < 0)
{
fprintf(stderr, "Error occurred when allocating output context: %d\n", ret);
return;
}
stream = avformat_new_stream(formatContext, nullptr);
if (!stream)
{
avformat_free_context(formatContext);
formatContext = nullptr;
fprintf(stderr, "Error occurred creating new stream");
return;
}
stream->codec->codec_tag = 0;
if (formatContext->oformat->flags & AVFMT_GLOBALHEADER)
{
stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
stream->codec->codec_id = AV_CODEC_ID_H264;
stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
stream->codec->bit_rate = 4096000; // 8192000; // 4096000; // 384000;
stream->codec->width = 1920; // 352
stream->codec->height = 1080; // 288
stream->codec->gop_size = 50;
AVRational tb;
tb.num = 1;
tb.den = 25;
stream->codec->time_base = tb;
//stream->codec->field_order = AVFieldOrder::AV_FIELD_UNKNOWN;
//stream->codec->color_primaries = AVColorPrimaries::AVCOL_PRI_BT470BG;
//stream->codec->color_trc = AVColorTransferCharacteristic::AVCOL_TRC_GAMMA22;
//stream->codec->colorspace = AVColorSpace::AVCOL_SPC_BT470BG;
//stream->codec->chroma_sample_location = AVChromaLocation::AVCHROMA_LOC_CENTER;
AVRational aratio;
aratio.num = 1;
aratio.den = 1;
stream->codec->sample_aspect_ratio = aratio;
// stream->codec->delay = 0;
// stream->codec->color_range = AVColorRange::AVCOL_RANGE_MPEG;
av_dump_format(formatContext, 0, formatContext->filename, 1);
if (!(formatContext->oformat->flags & AVFMT_NOFILE))
{
if (avio_open(&formatContext->pb, formatContext->filename, AVIO_FLAG_WRITE) < 0)
{
avformat_free_context(formatContext);
formatContext = nullptr;
fprintf(stderr, "Error occurred when opening output file.");
return;
}
}
avformat_write_header(formatContext, nullptr);
int frameIdx = 0;
int pts = 0;
int dts = 0;
int pkt_pos = 0;
int size = static_cast<int>(tmpRawFrameBuffer.size());
AVPacket pkt = { 0 };
av_init_packet(&pkt);
while (frameIdx < size)
{
pkt.data = tmpRawFrameBuffer[frameIdx];
pkt.size = tmpRawFrameSizes[frameIdx];
// debug purphose start
FILE* f;
char filename[MAX_PATH];
sprintf_s(filename, MAX_PATH, OUTPUT_PACKET_FILE_PATTERN_NAME, frameIdx);
auto err = fopen_s(&f, filename, "wb");
if (err != 0)
{
fprintf(stderr, "Could not open %s\n", OUTPUT_V_FILE_NAME);
exit(1);
}
fflush(stdout);
fwrite(pkt.data, 1, pkt.size, f);
fclose(f);
// debug purphose end
if (tmpRawFrameTypes[frameIdx] == VIDEO_I_FRAME)
{
pkt.flags |= AV_PKT_FLAG_KEY;
stream->codec->extradata_size = 50;
stream->codec->extradata = (uint8_t*)av_malloc(stream->codec->extradata_size);
memcpy(stream->codec->extradata, pkt.data, stream->codec->extradata_size);
}
pkt.pts = pts++;
pkt.dts = dts++;
/* rescale output packet timestamp values from codec to stream timebase */
// av_packet_rescale_ts(&pkt, stream->codec->time_base, stream->time_base);
pkt.pts = av_rescale_q(pkt.pts, stream->codec->time_base, stream->time_base);
pkt.dts = av_rescale_q(pkt.dts, stream->codec->time_base, stream->time_base);
pkt.duration = 512; // should be calculated (derived from FPS 25, and 12800)
pkt.pos = -1;
pkt.stream_index = stream->index;
auto ret = av_write_frame(formatContext, &pkt);
if (ret < 0)
{
fprintf(stderr, "Error while writing video frame: %d\n", ret);
break;
}
av_packet_unref(&pkt);
++frameIdx;
}
if (formatContext)
{
av_write_trailer(formatContext);
if (!(formatContext->oformat->flags & AVFMT_NOFILE)) avio_close(formatContext->pb); // close the output file
avformat_free_context(formatContext);
formatContext = nullptr;
}
}
</int>It seems, the packet from camera (buffered in tmpRawFrameBuffer vector) contains some headers, but I am not able to parse them, I do not understand the meaning of the header.
The first bytes of the I-frame packet looks like the dump bellow :
00 00 01 FC 02 19 F0 87 A0 23 73 41 B6 C0 01 00
00 00 00 01 67 4D 00 2A 95 A8 1E 00 89 F9 61 00
00 03 00 01 00 00 03 00 32 84 00 00 00 01 68 EE
3C 80 00 00 00 01 06 E5 01 19 80 00 00 00 01 65
B8 00 00 08 C7 B0 23 FF F7 80 EE FE 63 B6 FB F5
...The first bytes of the first P-frame :
00 00 01 FD E5 24 00 00 00 00 00 01 61 E0 22 27
FF D6 B0 D7 A4 2B 71 6B 19 C5 87 CA BB 8B BF 60
14 59 B4 00 CC BC 0F C0 9E FD 84 B5 FB C4 83 DB
5A 8B 80 FC EC D6 33 6D DE 10 96 6F 31 41 86 5C
D4 22 F9 33 48 5B CE 77 38 17 0C D6 DD C7 6C E8
...first bytes of next P-frame :
00 00 01 FD 5E 2F 00 00 00 00 00 01 61 E0 42 2F
FF E7 06 DD 3C 66 26 15 94 93 7A F1 30 8A 6D B8
AD DD 6B 0F 38 89 1D 1B 5C AC 44 6A D7 D1 21 3B
E2 29 F8 14 BB 98 1C 06 4D B6 10 BB DB B9 CA 4F
0B ED B1 A9 06 78 8C EC 06 6D 9F 4F 79 0C 35 5B
......
begining of next I-frame :
00 00 01 FC 02 19 F0 87 A2 23 73 41 75 89 01 00
00 00 00 01 67 4D 00 2A 95 A8 1E 00 89 F9 61 00
00 03 00 01 00 00 03 00 32 84 00 00 00 01 68 EE
3C 80 00 00 00 01 06 E5 01 1B 80 00 00 00 01 65
B8 00 00 0F 07 F0 7F F6 6C 69 43 0F F0 28 DF 97
...Does anybody know, how to fill correctly the extradata ? I just made a copy of first 50 bytes, but it seems, this is not correct.
Probably the headers are (AUD)(SPS)(PPS)(I-Slice)(PPS)(P-Slice)(PPS)(P-Slice) ... (AUD)(SPS)(PPS)(I-Slice) (http://stackoverflow.com/a/20686267/1699328), however, I do not know, how to extract data for the
stream->codec->extradata
I tried to get some inspiration in this post H.264 muxed to MP4 using libavformat not playing back, but I am not able to figure out what are values of spsFrameLen, ppsFrameLen and spsFrame.
The result of the muxer (first and last bytes of the mp4 file) :
00 00 00 20 66 74 79 70 69 73 6F 6D 00 00 02 00
69 73 6F 6D 69 73 6F 32 61 76 63 31 6D 70 34 31
00 00 00 08 66 72 65 65 00 26 2E 6D 6D 64 61 74
00 00 00 0D FC 02 19 F0 87 A0 23 73 41 B6 C0 01
00 00 00 00 16 67 4D 00 2A 95 A8 1E 00 89 F9 61
00 00 03 00 01 00 00 03 00 32 84 00 00 00 04 68
EE 3C 80 00 00 00 05 06 E5 01 19 80 00 01 C0 87
65 B8 00 00 08 C7 B0 23 FF F7 80 EE FE 63 B6 FB
F5 97 A8 6B 48 39 61 99 FD 99 27 41 F2 78 54 EE
D1 38 8E E8 18 DD 05 E4 BA F4 EB 69 CF 91 5C 34
...
...
...
95 B8 D8 D4 C3 AF A1 BA AC 28 F0 D4 D4 7C 48 9A
0C A6 8C 4C 98 00 00 05 1E 6D 6F 6F 76 00 00 00
6C 6D 76 68 64 00 00 00 00 00 00 00 00 00 00 00
00 00 00 03 E8 00 00 13 B0 00 01 00 00 01 00 00
00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00
00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 02 00 00 04 48 74 72 61
6B 00 00 00 5C 74 6B 68 64 00 00 00 03 00 00 00
00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 13
B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 40 00 00 00 07 80 00 00 04 38 00 00 00 00 00
24 65 64 74 73 00 00 00 1C 65 6C 73 74 00 00 00
00 00 00 00 01 00 00 13 B0 00 00 00 00 00 01 00
00 00 00 03 C0 6D 64 69 61 00 00 00 20 6D 64 68
64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 32
00 00 00 FC 00 55 C4 00 00 00 00 00 2D 68 64 6C
72 00 00 00 00 00 00 00 00 76 69 64 65 00 00 00
00 00 00 00 00 00 00 00 00 56 69 64 65 6F 48 61
6E 64 6C 65 72 00 00 00 03 6B 6D 69 6E 66 00 00
00 14 76 6D 68 64 00 00 00 01 00 00 00 00 00 00
00 00 00 00 00 24 64 69 6E 66 00 00 00 1C 64 72
65 66 00 00 00 00 00 00 00 01 00 00 00 0C 75 72
6C 20 00 00 00 01 00 00 03 2B 73 74 62 6C 00 00
00 93 73 74 73 64 00 00 00 00 00 00 00 01 00 00
00 83 61 76 63 31 00 00 00 00 00 00 00 01 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 80
04 38 00 48 00 00 00 48 00 00 00 00 00 00 00 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 18 FF FF 00 00 00 2D 61 76 63 43 01 4D 00 2A
FF E1 00 16 67 4D 00 2A 95 A8 1E 00 89 F9 61 00
00 03 00 01 00 00 03 00 32 84 01 00 04 68 EE 3C
80 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00
01 00 00 00 7E 00 00 02 00 00 00 00 1C 73 74 73
73 00 00 00 00 00 00 00 03 00 00 00 01 00 00 00
33 00 00 00 65 00 00 00 34 73 74 73 63 00 00 00
00 00 00 00 03 00 00 00 01 00 00 00 3B 00 00 00
01 00 00 00 02 00 00 00 37 00 00 00 01 00 00 00
03 00 00 00 0C 00 00 00 01 00 00 02 0C 73 74 73
7A 00 00 00 00 00 00 00 00 00 00 00 7E 00 01 C0
C7 00 00 24 EE 00 00 2F 67 00 00 1D 83 00 00 2E
8F 00 00 30 B6 00 00 2F 44 00 00 2F 50 00 00 34
6B 00 00 30 BE 00 00 31 0C 00 00 31 E7 00 00 30
EA 00 00 31 4E 00 00 31 A8 00 00 32 21 00 00 31
E6 00 00 31 B5 00 00 31 14 00 00 31 AF 00 00 31
9D 00 00 33 60 00 00 32 11 00 00 32 4C 00 00 31
F0 00 00 32 91 00 00 43 43 00 00 44 29 00 00 44
EC 00 00 44 20 00 00 44 86 00 00 45 AD 00 00 47
47 00 00 46 9F 00 00 46 D9 00 00 47 BE 00 00 48
CD 00 00 3E 50 00 00 40 98 00 00 41 0E 00 00 40
43 00 00 41 07 00 00 41 BB 00 00 41 FF 00 00 30
5E 00 00 33 C7 00 00 34 B7 00 00 33 F1 00 00 33
0D 00 00 32 DB 00 01 89 86 00 00 3B E1 00 00 3C
55 00 00 3C 64 00 00 3C B7 00 00 3C FD 00 00 3E
54 00 00 3E C5 00 00 3E 1C 00 00 3E 94 00 00 3E
44 00 00 3E D7 00 00 3F CC 00 00 3E D6 00 00 40
00 00 00 40 4D 00 00 40 04 00 00 3F A9 00 00 40
82 00 00 41 0F 00 00 41 64 00 00 41 E5 00 00 42
1E 00 00 42 2C 00 00 42 80 00 00 42 4D 00 00 43
9F 00 00 43 DA 00 00 44 45 00 00 44 21 00 00 44
B7 00 00 45 22 00 00 45 E3 00 00 45 BF 00 00 46
18 00 00 47 4B 00 00 45 05 00 00 47 34 00 00 46
60 00 00 46 97 00 00 46 66 00 00 46 29 00 00 46
38 00 00 47 1D 00 00 47 42 00 00 47 18 00 00 47
13 00 00 46 52 00 00 47 48 00 00 46 F8 00 01 BE
E3 00 00 3F 56 00 00 3B 32 00 00 38 F8 00 00 37
56 00 00 36 2D 00 00 35 DA 00 00 34 6B 00 00 3E
BE 00 00 3E B5 00 00 3F 33 00 00 3F AC 00 00 3F
38 00 00 42 32 00 01 1B DC 00 01 80 50 00 01 14
06 00 00 C2 BB 00 00 96 12 00 00 6D EC 00 00 54
E6 00 00 3A AC 00 00 32 00 00 00 2F 0A 00 00 2D
F1 00 00 1B 7F 00 00 00 1C 73 74 63 6F 00 00 00
00 00 00 00 03 00 00 00 30 00 0F DD AB 00 1F 7D
9E 00 00 00 62 75 64 74 61 00 00 00 5A 6D 65 74
61 00 00 00 00 00 00 00 21 68 64 6C 72 00 00 00
00 00 00 00 00 6D 64 69 72 61 70 70 6C 00 00 00
00 00 00 00 00 00 00 00 00 2D 69 6C 73 74 00 00
00 25 A9 74 6F 6F 00 00 00 1D 64 61 74 61 00 00
00 01 00 00 00 00 4C 61 76 66 35 37 2E 32 33 2E
31 30 30Thanks a lot for any advices.
-
On-demand and seamless transcoding of individual HLS segments
5 janvier 2024, par Omid AriyanBackground


I've been meaning to implement on-demand transcoding of certain video formats such as ".mkv", ".wmv", ".mov", etc. in order to serve them on a media management server using ASP.NET Core 6.0, C# and ffmpeg.


My Approach


The approach I've decided to use is to serve a dynamically generated .m3u8 file which is simply generated using a segment duration of choice e.g. 10s and the known video duration. Here's how I've done it. Note that the resolution is currently not implemented and discarded :


public string GenerateVideoOnDemandPlaylist(double duration, int segment)
{
 double interval = (double)segment;
 var content = new StringBuilder();

 content.AppendLine("#EXTM3U");
 content.AppendLine("#EXT-X-VERSION:6");
 content.AppendLine(String.Format("#EXT-X-TARGETDURATION:{0}", segment));
 content.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
 content.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
 content.AppendLine("#EXT-X-INDEPENDENT-SEGMENTS");

 for (double index = 0; (index * interval) < duration; index++)
 {
 content.AppendLine(String.Format("#EXTINF:{0:#.000000},", ((duration - (index * interval)) > interval) ? interval : ((duration - (index * interval)))));
 content.AppendLine(String.Format("{0:00000}.ts", index));
 }

 content.AppendLine("#EXT-X-ENDLIST");

 return content.ToString();
}

[HttpGet]
[Route("stream/{id}/{resolution}.m3u8")]
public IActionResult Stream(string id, string resolution)
{
 double duration = RetrieveVideoLengthInSeconds();
 return Content(GenerateVideoOnDemandPlaylist(duration, 10), "application/x-mpegURL", Encoding.UTF8);
}



Here's an example of how the .m3u8 file looks like :


#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-INDEPENDENT-SEGMENTS
#EXTINF:10.000000,
00000.ts
#EXTINF:3.386667,
00001.ts
#EXT-X-ENDLIST



So the player would ask for 00000.ts, 00001.ts, etc. and the next step is to have them generated on demand :


public byte[] GenerateVideoOnDemandSegment(int index, int duration, string path)
{
 int timeout = 30000;
 int totalWaitTime = 0;
 int waitInterval = 100;
 byte[] output = Array.Empty<byte>();
 string executable = "/opt/homebrew/bin/ffmpeg";
 DirectoryInfo temp = Directory.CreateDirectory(System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()));
 string format = System.IO.Path.Combine(temp.FullName, "output-%05d.ts");

 using (Process ffmpeg = new())
 {
 ffmpeg.StartInfo.FileName = executable;

 ffmpeg.StartInfo.Arguments = String.Format("-ss {0} ", index * duration);
 ffmpeg.StartInfo.Arguments += String.Format("-y -t {0} ", duration);
 ffmpeg.StartInfo.Arguments += String.Format("-i \"{0}\" ", path);
 ffmpeg.StartInfo.Arguments += String.Format("-c:v libx264 -c:a aac ");
 ffmpeg.StartInfo.Arguments += String.Format("-segment_time {0} -reset_timestamps 1 -break_non_keyframes 1 -map 0 ", duration);
 ffmpeg.StartInfo.Arguments += String.Format("-initial_offset {0} ", index * duration);
 ffmpeg.StartInfo.Arguments += String.Format("-f segment -segment_format mpegts {0}", format);

 ffmpeg.StartInfo.CreateNoWindow = true;
 ffmpeg.StartInfo.UseShellExecute = false;
 ffmpeg.StartInfo.RedirectStandardError = false;
 ffmpeg.StartInfo.RedirectStandardOutput = false;

 ffmpeg.Start();

 do
 {
 Thread.Sleep(waitInterval);
 totalWaitTime += waitInterval;
 }
 while ((!ffmpeg.HasExited) && (totalWaitTime < timeout));

 if (ffmpeg.HasExited)
 {
 string filename = System.IO.Path.Combine(temp.FullName, "output-00000.ts");

 if (!File.Exists(filename))
 {
 throw new FileNotFoundException("Unable to find the generated segment: " + filename);
 }

 output = File.ReadAllBytes(filename);
 }
 else
 {
 // It's been too long. Kill it!
 ffmpeg.Kill();
 }
 }

 // Remove the temporary directory and all its contents.
 temp.Delete(true);

 return output;
}

[HttpGet]
[Route("stream/{id}/{index}.ts")]
public IActionResult Segment(string id, int index)
{
 string path = RetrieveVideoPath(id);
 return File(GenerateVideoOnDemandSegment(index, 10, path), "application/x-mpegURL", true);
}
</byte>


So as you can see, here's the command I use to generate each segment incrementing -ss and -initial_offset by 10 for each segment :


ffmpeg -ss 0 -y -t 10 -i "video.mov" -c:v libx264 -c:a aac -segment_time 10 -reset_timestamps 1 -break_non_keyframes 1 -map 0 -initial_offset 0 -f segment -segment_format mpegts /var/folders/8h/3xdhhky96b5bk2w2br6bt8n00000gn/T/4ynrwu0q.z24/output-%05d.ts



The Problem


Things work on a functional level, however the transition between segments is slightly glitchy and especially the audio has very short interruptions at each 10 second mark. How can I ensure the segments are seamless ? What can I improve in this process ?