google / sagetv

SageTV is a cross-platform networked DVR and media management system
http://forums.sagetv.com/
Apache License 2.0
265 stars 174 forks source link

Add Remuxing Support to MediaServer #138

Closed enternoescape closed 8 years ago

enternoescape commented 8 years ago

I just decided to tinker around with the proposed solution in the thread below. I was able to implement MPEGParser for use on the MediaServer last night. I also think I was able to overcome the random crashing mentioned in the thread and so far, I haven't seen any files being stuck until I restart SageTV. I able to make SageTV crash sometimes by closing the Remuxer twice, so the solution there was to just make it null once it has been closed. I also made it crash by overloading it with too much data at one time, which I solved by forcing the data to be fed in smaller chunks.

http://forums.sagetv.com/forums/showthread.php?t=62406

I was really impressed at how easy it was to get working. The bits I'm working on right now are just optimizing.

I noticed that MPEG-TS output only worked correctly when I fed it data in 188 byte increments. If I used anything bigger, the resulting video is playable, but corrupted. MPEG-PS output only complained when I went a lot higher than 64KB (around 2MB). Do these limitations sound familiar?

For setup, I used the suggestion of "REMUX_SETUP Format Channel InitSize." I implemented retaining the data used for detection, then once detection is successful, the data is written feed into pushData in 188 byte or 64KB chunks per the reasons in the above paragraph. I also added a check that if more than 5 seconds of time according to the container passed and the format has been detected to continue anyway even if we have not reached InitSize. That way you don't get stuck for a long time on low bitrate streams. Also if the InitSize is too little for the format to be detected, it will double in size up to 5MB before it will discard the buffered data and continue to buffer again. That should be way more than enough data based on my observations. After successful detection, the buffer is replaced with a 64KB buffer since that's the largest chunk it could possibly need to deal with when copying to the remuxer.

I was wondering about any suggestions on feedback to the network encoder so it can know when initialization is done and remuxing has actually started. This would be helpful to provide more seamless channel changes for example. Could I just add another command that allows the network encoder to query the current status of the remuxer?

The only downside I see to using the remuxing like this is if for some reason the network connection is disrupted. The remuxer doesn't appear to use any kind of offset, so it's unclear if you could actually add an offset as an option.

Narflex commented 8 years ago

Groovy, nice work. :) I'm not surprised at all by crashes on double close or requiring 188 byte alignment for incoming TS data (we have that alignment requirement on playback on the extenders as well). But, I would expect it to work with larger buffer sizes as well as long as they are multiples of 188. Feeding it 188 bytes at a time would be highly inefficient, so if you're seeing problems with sizes that are multiples of 188 as well, let me know and I can try to figure out what's going wrong.

As for the large buffers...there's likely some max size we are allocating buffers at and 2MB sound like a reasonable number we would have used. If you want to know exactly, let me know and I can dig into that code to figure out what it is.

As for the feedback...you are going to want something in this area. Maybe add a different variant of the WRITE call such as REMUX_WRITE which then also returns the current size of the outputted data; and maybe even a status for whether the format has been detected yet (if you find that useful). The most important thing here is that when it calls GET_FILE_SIZE over the network encoder RPC you'll want to be sure it's returning the size of the remuxed output file that's been written out to disk and NOT the size of the data it's sent into the remuxer. With this feedback, you would then know that size and can respond correctly.

And I wouldn't worry much about the network connection getting dropped; that pretty much never happens on LANs nowadays. And even if it does, SageTV's halt detector will kick in because the recording file has stopped growing and then it'll end up stopping and restarting the capture device in an attempt to recover (and it would likely recover then if the drop was due to a network anomaly).

enternoescape commented 8 years ago

I did try 1880 thinking similarly and that caused the TS remuxed output to be corrupted too. As far as I could determine, the limitation wasn't in the first method called in native code. I think it might be a little deeper. I thought it was interesting that PS is more tolerant. I also just in case I was somehow running on more than one thread unknowingly tried synchronizing the method; that did nothing helpful. :)

enternoescape commented 8 years ago

You don't need to dig into the code unless you're actually curious. I agree that 188 is rather inefficient, but I can live with it for now. It didn't hinder the file being written quickly enough.

Narflex commented 8 years ago

Wait...I need to clarify something with the 188 byte thing. Were you saying that if you had it configured for MPEG2-TS output and then we also feeding it MPEG2-TS input...that you then needed to only give it 188 byte blocks in that case? I misread this before as when you gave it MPEG2-TS input it required 188 byte block inputs (regardless of output format).

If the input is already MPEG2-TS; then you really shouldn't even need to do the remuxing (although it then can also fix PTS issues relating to ad insertion, so I guess there is a benefit to remuxing the TS into TS again in that case). SageTV always defaulted to MPEG2-PS output; so if you just plan on having MPEG2-PS as your default output...and then if somebody decides to change that to MPEG2-TS, it then needs to do 188 byte blocks...that would sound fine to me then. :) Defaults should always work the best...and if you want to go mucking around and changing things, then don't expect the changes to give you the best performance has always been fair in my mind.

enternoescape commented 8 years ago

I was testing MPEG2-TS to MPEG2-TS (only allowed 188-bytes at a time) and MPEG2-TS to MPEG2-PS. I have it set to use 188 bytes for TS output and 64K for PS output. I wouldn't actually mind being able to go back to PS; it always seems to work best with Comskip. :)

Many users are having problems with their cable providers inserting local commercials that badly disrupt the timeline, so remuxing is a must for them. 95% of the time I don't need to remux anything for my own setup, but there's that 5% of the time when I end up having to remux the raw stream or SageTV can't play it back. Also some Comcast content will not play at all in many situations without remuxing as it comes in because they do some strange things with the the order of the decode timestamps. So I think that even if it's TS to TS, it's worth it. I know you touched some of these points in your own comment.

enternoescape commented 8 years ago

Instead of waiting on feedback from a call to REMUX_WRITE (I kind of like the async nature of WRITE), I decided it would be more flexible to call what I've named REMUX_STATUS. It currently only accepts INIT as a parameter, but this leaves some flexibility in there in case something is thought of in the future.

I noticed that the SIZE call will do well enough. Based on the frequency of transfers being higher than the queries for the size of the file, I think it would be more efficient to just call SIZE when it's actually requested of the network encoder instead of returning the current size for each write when there's nothing to really useful to do with that information. I'm getting the current file size from fileChannel. Let me know if there's a more efficient way to get that information when remuxing.

enternoescape commented 8 years ago

I just added REMUX_SWITCH which changes the file out after flushing the last output from the remuxer. That way the remuxer doesn't need to be set up again and the transitions are very smooth. It takes the same format as WRITEOPEN and does the same checks. The only difference is that when it closes the file, it doesn't also close the remuxer. I have tested this approach on several different content types and it works very nicely. :) Basically I replaced FileOutputStream with an anonymous OutputStream implementation that buffers the output of the remuxer and writes the buffered data out to whatever the current FileOutputStream is. On the OpenDCT side of things, I am selecting what looks like a good spot to split the stream, then it calls REMUX_SWITCH.

I take it back about it being smooth. After a few further attempts on using SWITCH in this manner, I need to re-evaluate how I'm determining the switching point and at the moment I'm working on putting that task on the SageTV side of things. I'm working on a few calls so you can tell it you need to switch, it lets you know if it succeeded and if it tells you that it didn't, you just feed it more data and then query again. I've found several examples in the native code and even a section of Java code that gives me a decent idea of what I should be looking for. It looks like you're handling the data that's already been remuxed, is that correct?

I also added the ability to do buffering on the SageTV side when remuxing which is needed for channel previews. That was needed because there's no way to do that efficiently from the network encoder's perspective.

I noticed on further analysis of what you're actually doing, that the method being used should only work with MPEG2 video. Unfortunately a lot of us have channels in H.264. I can't seem to find any information about MPEG-PS and H.264 headers. I'm finding a lot of information suggesting that H.264 should not be getting muxed into a PS file.

Also apparently the remuxer can strip the PAT/PMT packets from the stream entirely. I was trying to figure out why the Client and Placeshifter wouldn't play the files even though the file was clearly growing and other media players were willing to play them. I ran MediaInfo on a few of them and it report that the PAT and PMT packets were missing. Is there a setting I might be missing?

Narflex commented 8 years ago

A few things to reply to here. :)

For the file size status; I agree about the nicety of the asynchronous part of WRITE. This could be dealt with even when it does replies of the size by having a multi-threaded receiver on the network encoder end where you process the replies in parallel...however, having written one of these for the way we send data to the extender, it's easy to make mistakes and have it break and get out of sync...so resorting to using SIZE when its needed isn't all that bad. I'm not sure I followed what you were talking about wrt REMUX_STATUS.

What's probably the most ideal way to deal with the file size issue is to have another property setting which indicates that the SageTV server itself should get the file size. Then in NetworkCaptureDevice.java you just have it check the local file size there so that won't even then require an RPC to the network encoder (and then potentially another one back to the SageTV server just to make that same call).

I do see the point about remuxing TS back into TS; so you do want to support that.

For the SWITCH operation; that should be something you can handle on your end...the way we've always done it is to break the stream at either an I Frame (for MPEG2) or an IDR (for H264). So if you detect that case and then switch it at that point, you should be fine. Remember, you should not return from the SWITCH call until you have actually completed the SWITCH operation (which means its OK to block in that for a very short amount of time, generally it'll take up to a half second to detect the right boundary due to 0.5 second GOPs).

And I would expect the remuxer to strip the PAT/PMT from the TS stream because it's moving them to different PIDs so it can't retain those from before. I would expect it to write out new ones though; but I don't recall if it actually does that (I didn't write that code). Although I took a quick look at it, and it appears that it will write out a PAT every 2000 packets and a PMT every 8000 packets. So if you have remuxed files where MediaInfo is complaining there's no PAT/PMT, send me the first couple MBs of the TS file and I'll take a look at it. (but from the code the first packet TS packet in the file should be PAT and the second one PMT).

As for H264...I don't think I've ever seen that in an MPEG2-PS...so I'd say stick with TS for any H264 channels.

Hopefully I got all your questions...let me know if you have more. :)

enternoescape commented 8 years ago

Thank you for so much help. You've been awesome. :)

This is my experience with TS as input and PS as output. I learned that switching at an I frame on the input stream wasn't good enough. What was happening when I was watching live TV is I would switch at an I frame (starting the new file with the detected I frame) and the player would lock up while the new file continued to be written. If I pushed the I frame just before switching the file, it would transition, but the audio would drop out, then if I skipped back a little in the live recording, the audio would come back. I learned early in developing OpenDCT not to return OK until everything was ready. :) These results are why I changed my focus to the output of the remuxer, but if you're saying I should be able to do this on the input side, I'll try to figure out what isn't doing what I think it's doing.

In OpenDCT, when I SWITCH while remuxing with FFmpeg, I can do it on any key video packet and it always works really well whether I'm using TS or PS. I also have switching working well with the raw output option too, so this is a little perplexing to me.

As far as I could determine, it didn't actually change the PID's. I scanned a 3.7GB file it created with one of the functions I wrote in OpenDCT and it contained absolutely no packets with the PID 0 (PAT). I didn't have a function for finding a loose PMT, but I have a feeling wasn't there either. How would you prefer I get you a sample? Also do you want the unprocessed file, the processed file or both?

Narflex commented 8 years ago

So I'm not sure at all that you can do this on the input side or not. My assumption would be that you could..however, that assumption may be wrong. :) The remuxer is likely buffering the input data to some degree in order to keep the PS packet sizes somewhat consistent. However, I would also assume it employs some kind of I-Frame detection and that it would start a new PS packet when it encounters an I-Frame since that is generally desirable.

I took a quick look at the code...and I think it's doing some kind of alignment, but I'm not sure.

As for not changing the PIDs...I figured it would...but I'm not too surprised if it isn't doing that. :)

For my own analysis, I'd like the input and output files you have. Just upload them to Google drive and make it shareable and post the link here so I can download them and take a look.

enternoescape commented 8 years ago

I made a little progress over lunch today, so I want to see if I can work this one out myself. I really need to write more C++ (for something other than a microcontroller) and I feel like this is a good opportunity to learn something. I like a good challenge and I think I figured out why there are alignment issues in the native code when feeding TS packets in sizes larger than 188.

I also think I figured out in the native code why on high bitrate streams, video PES packets are occasionally missing when TS is the output.

Narflex commented 8 years ago

Great to hear it. :) I don't know how deep your knowledge of MPEG standards is; but if you need any help understanding why certain things are being done at that level, always feel free to ask...I've written far too many MPEG parsers. :)

enternoescape commented 8 years ago

I'm not an expert by any means, but I will say I know a lot more about how it all works than I did a year ago. :) In this case I have the advantage of the code in place already being fairly solid, so all I'm really looking for is the quirk that's making it not work as expected.

enternoescape commented 8 years ago

From what I am able to determine, BlockBufferTSDump (TSBuilder.c) is the only method that uses PushTSBlockData (TSBuilder.c) and BlockBufferTSDump is a callback set by OpenRemuxStream (Remux.c). So if we are looking at the same file, basically those PAT and PMT packets will never be injected, or at least not for the reasons you would think. Just to verify a few things I set up some additional logging in these methods and as expected, the logging never happened. The method that's actually being used is ParseData (TSParser.c). I verified that the packets are in fact taking this route, but when the packet is a PAT or PMT packet, it is processed, then discarded. I see a path to getting this working as expected, but after seeing what route the packets are taking, I'm not even sure discontinuities are being corrected.

enternoescape commented 8 years ago

I figured out how to get the PAT and PMT packets injected. I was following the code all the way to TSAVStreamHook (TSSplitter.c) which is the callback that ultimately queues the packets for writing and also happens to keep a count of how many it has written. I didn't see anywhere else that updated this counter, so I figured it was safe to use for intervals. I made a few changes to that method and suddenly PAT and PMT packets at the right intervals started being injected into the TS output. PushPat and PushPmt looked like they were only in use at the end of some code for detecting an ATSC channel.

//start build video or audio from start frame (PES header)
if ( ts->builder_state >= 2 ) 
{
    int packet_increment = 1;

    // Insert PAT and PMT packets at interval.
    if (ts->ts_packet_num % 2000 == 0)
    {
        PushPat( ts->ts_builder );
        packet_increment++;
    }

    if (ts->ts_packet_num % 8000 == 0)
    {
        PushPmt( ts->ts_builder, ts->program_id );
        packet_increment++;
    }

    PushAVPacketData( ts->ts_builder, ts->program_id, av_info->sub_channel, 
              av_info->start_group_flag, av_info->data, av_info->bytes );

    ts->ts_packet_num += packet_increment;
}

I also had to bump up the following in TSBuilder.h to keep the queue from overflowing:

#define PACKET_POOL_NUMBER  (8*1024/188+3)
Narflex commented 8 years ago

Groovy, nice detective work. :)

enternoescape commented 8 years ago

I noticed that on TS output PCR packets are being dropped. I think this might be the cause of some audio drift I was seeing while watching live TV. There certainly are a lot of little issues with this code path. :)

Narflex commented 8 years ago

PCR shouldn't affect anything. I've never seen a modern decoder that even uses it. Audio/video sync should be fully maintained by the PTS values. The only time I ever see drift anymore is due to underflow...but we prevent that from occurring in the extenders. If you have a repro case, I'd be more than happy to look at it.

Jeff Kardatzke Sent from my Android On May 18, 2016 6:06 PM, "Joseph Shuttlesworth" notifications@github.com wrote:

I noticed that on TS output PCR packets are being dropped. I think this might be the cause of some audio drift I was seeing while watching live TV. There certainly are a lot of little issues with this code path. :)

— You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-220201677

enternoescape commented 8 years ago

The live TV situation was with the SageTV client. I didn't do much testing with the extender. Also, while I can say that while SageTV can decode the streams without any real issues, Windows Media Player (which can play the raw stream surprisingly) and VLC cannot. FFmpeg doesn't have any complaints about the files either. I guess your comment about a modern decoder might be the key word. I found the location where it appears to be discarding all of the packets containing PCR data because it can't parse them correctly and think it would be better to fix it. Some people other than myself prefer that the files are able to playback in places other than SageTV. I'll let you know if I get stuck.

JustFred51 commented 8 years ago

Not sure if this is related, but I've had repeated similar cases with playback on HD200's where the audio mysteriously fades out for 1-2 seconds and then fades back in. Occurs on multiple systems running Sage 7.1.9, but not using OpenDCT. Although it most frequently occurs while watching live TV (the nightly news), it's also occurred during playback of Sage-recorded TV series. In every case, skipping back and re-playing the segment repeats the same audio problem. These are .mpeg files that were recorded OTA from an HDHR tuner. If it'll help, I can probably provide an affected file.

enternoescape commented 8 years ago

@JustFred51 These issues I'm talking about right now are just with TS output from the remuxer built into SageTV. Typically no one really uses this code path and I'm trying to shape it up so H.264 content can be fed through it reliably. My plans are to start with PS, then if the video isn't MPEG-1 or MPEG-2, switch over to TS. The PS (.mpg) output appears to be ok.

@Narflex You're right (as I'm sure you expected :)) about the extender. The audio isn't drifting at all.

enternoescape commented 8 years ago

Unrelated, but I did figure out why 188 per transfer was required. The issue was that the output packet queue only had enough play for one additional packet. I bumped that value up 7 more and now I can push 7 packets at a time which is a typical number of packets for RTP, so I think that's a good number to work with. This change alone got CPU usage in the SageTV process for one stream down from 4% to 0-1%.

I'll try to commit something tonight. I just didn't want to commit anything I haven't had much time testing.

enternoescape commented 8 years ago

I confirmed that it's not that it's dropping the PCR packets so much as it's wiping the PCR data out and clearing the adaptation field PCR flag. The culprit is in BuildTSHeader (TSBuilder.c) which basically wipes out all of the adaptation data. I suppose this would not be a problem since this data isn't used for anything as far as SageTV is concerned.

enternoescape commented 8 years ago

What is the code under ./native/ax/Native2.0/NativeCore/TSParser.c? It looks like a more complete implementation. The code that I have been working with is under ./native/ax/TSnative/TSParser.c.

Narflex commented 8 years ago

I didn't even realize there was still code under native/ax/TSnative...apparently that's the old school remuxer/TS handling code. The stuff in ax/Native2.0/NativeCore is the updated version that was done to handle more stuff. We barely used the remuxer from the Java level at all (it was only for the MediaMVP)...and now I recall telling Qian that we should just leave the original code for that in there for compatibility, and he didn't need to worry about merging them together (many years ago).

So...ideally they would all get merged together and the Java remuxer would use the Native2.0 code; but that may be a much larger undertaking and likely non-trivial (otherwise we probably would have done it). For the remuxing done by our own capture code...I know it is using Native2.0.

@qianzhang5 Any comments on this?

@qianzhang5: Jeff is right.

enternoescape commented 8 years ago

I had a bad feeling that you were about to essentially tell me I've wasted 3 days looking at the wrong code. I'm starting to wish I had asked, since I would have been looking at getting us on the newer code instead of fixing little issues with the old code.

Narflex commented 8 years ago

I wouldn't say you've wasted three days...there should likely be lots of overlap in the structure of the two parts, especially the higher level remuxing that's done.

enternoescape commented 8 years ago

I actually was trying to find a silver lining in this. I think from looking at how the simpler version works, I will have an easier time following what's going on in the more complete version as I port it over to being able to be used in Java. (I think that's pretty much what you just said. :))

enternoescape commented 8 years ago

I finally got around to taking a closer look at the feasibility of adding use of the newer code. I was originally thinking I could just upgrade the current native code that uses the old remuxer to use the newer remuxer, but it looks like there are places in SageTV that still use the old remuxer code to determine container formats.

I guess I will need to create a new .dll for Windows, a new .so for Linux and a new Java class to pull the JNI in.

Narflex commented 8 years ago

That's interesting..I didn't realize it was using the old code for format detection still...but I guess that makes sense since they are in the same library.

enternoescape commented 8 years ago

So if I'm looking for a rough guide on how to use this code correctly, ./native/ax/Native2.0/RemuxFile/RemuxFile.c is the right place to be looking? Or do you have a better suggestion?

I can see that ultimately just uses ./native/ax/Native2.0/Remuxer.c, so I guess I should be looking around in there.

Narflex commented 8 years ago

Yeah, that should lead you down the right path. That'll point to native/ax/Native2.0/NativeCore/Remuxer.c which then has more high level remuxing code in it. You'll need to use something different than the file based one; but by looking at that file you should be able to figure out how to set it up for something that's memory based instead of file based.

enternoescape commented 8 years ago

I was really confused for a little while until I noticed that in ./native/ax/Native2.0/NativeCore/NativeCore.h, there is a macro that reads #define NULL ((void *)0). NativeCore is entirely done in C. Leaving this macro intact from what I understand isn't valid in C++ and prevents any possibility of compiling a Windows DLL. I added

#ifdef NULL
#define NULL 0
#endif

to the header for the DLL I am creating and it fixed the issue, so it will actually compile now, but I'm not sure what consequences this might have down the road. Is there a reason why NULL was defined? If we need to be positive of the value, could we possibly use a less global macro?

qianzhang5 commented 8 years ago

I can't remember the reason now. It probably was for cross-platform compatibility in embedded c in the early days. I don't think there is a risk here.

On Fri, Jun 3, 2016 at 10:06 PM, Joseph Shuttlesworth < notifications@github.com> wrote:

I was really confused for a little while until I noticed that in ./native/ax/Native2.0/NativeCore/NativeCore.h, there is a macro that reads

define NULL ((void *)0). NativeCore is entirely done in C. Leaving this

macro intact from what I understand isn't valid in C++ and prevents any possibility of compiling a Windows DLL. I added

ifdef NULL

define NULL 0

endif

to the header for the DLL and it fixed the issue, so it will actually compile now, but I'm not sure what consequences this might have down the road. Is there a reason why NULL was defined? If we need to be positive of the value, could we possibly use a less global macro?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-223736901, or mute the thread https://github.com/notifications/unsubscribe/AMQtgE1do4gn7nOHheBRqNzGAylfHiAPks5qIQfjgaJpZM4IeL_U .

enternoescape commented 8 years ago

Now that I am able to create and close the newer remuxer in the JVM, I moved on to pushing data into it. I noticed that what comes out is actually messages and data in a struct. I see an example of how to deal with all of the messages in /third_party/Microsoft/TSSplitter/TSSplitFilter.cpp. It's a fair amount of code to just copy, so I was wondering what the preference would be here or if a lot of that code isn't even needed to detect and remux the stream.

Narflex commented 8 years ago

Preference between which options?

Jeff Kardatzke Sent from my Android On Jun 6, 2016 7:10 PM, "Joseph Shuttlesworth" notifications@github.com wrote:

Now that I am able to create and close the newer remuxer in the JVM, I moved on to pushing data into it. I noticed that what comes out is actually messages and data in a struct. I see an example of how to deal with all of the messages in /third_party/Microsoft/TSSplitter/TSSplitFilter.cpp. It's a fair amount of code to just copy, so I was wondering what the preference would be here or if a lot of that code isn't even needed to detect and remux the stream.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-224116200, or mute the thread https://github.com/notifications/unsubscribe/ANEIDCw2TlFetHcw0uiXBfdWUakt1Baiks5qJKjIgaJpZM4IeL_U .

enternoescape commented 8 years ago

I could have worded that better. Should I just copy it verbatim with minor adjustments, are there any suggestions on what parts really shouldn't be needed or would you rather I just use my best judgement?

Narflex commented 8 years ago

Use your best judgment, unless Qian chimes in with advice

Jeff Kardatzke Sent from my Android On Jun 6, 2016 8:20 PM, "Joseph Shuttlesworth" notifications@github.com wrote:

I could have worded that better. Should I just copy it verbatim with minor adjustments, are there any suggestions on what parts really shouldn't be needed or would you rather I just use my best judgement?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-224127375, or mute the thread https://github.com/notifications/unsubscribe/ANEIDEq8jrRuPsatqGk7elJBQ6tVQ-Mkks5qJLkxgaJpZM4IeL_U .

enternoescape commented 8 years ago

I think I was looking at this a little too intensely. Getting remuxed data out was a lot easier than I was making it out to be. Very exciting. :)

Narflex commented 8 years ago

Awesome!

Jeff Kardatzke Sent from my Android On Jun 6, 2016 10:08 PM, "Joseph Shuttlesworth" notifications@github.com wrote:

I think I was looking at this a little too intensely. Getting remuxed data out was a lot easier than I was making it out to be. Very exciting. :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-224144300, or mute the thread https://github.com/notifications/unsubscribe/ANEIDILKoBwVR9COcf6tSQQ2lFT7RFy6ks5qJNKAgaJpZM4IeL_U .

enternoescape commented 8 years ago

One of the things I think would be desirable is that is if the stream does not have MPEG-1 or MPEG-2 video that the container should automatically be changed over to TS if the remuxer was going to output PS. I found a function in Remuxer.c that would make you think it would be able to do this based on it's name (ChangeRemuxOutputFormat), but if I call that after the format has been detected, nothing is written. I can see that function migrates the DUMP callback and associated context, so I think this issue has more to do with changing the format at that point is simply wiping the detected stream info, causing the remuxer to essentially drop everything because it doesn't know what you want.

The workaround that I am using right now is to just re-open the remuxer setup to output TS which I guess is ok since I'm buffering the data until the format is detected, then flushing the remuxer queue and pushing the data in from the start (which nets me a few extra seconds of video). Since detection is more of an inline function with the newer remuxer, I had to be a little more clever so I wouldn't essentially dump some of the stream during detection which is what it appears to do with BDA devices. I know that having those few extra seconds buffered makes playback start faster, so this buffer during detection is very desirable.

enternoescape commented 8 years ago

I got it all working within the framework that I built for the older remuxer. All I have left to work out now is getting all of the switching correct and I'll finally have something to commit! Of course that might be another week or two being this doesn't really pay the bills. :) I'd like to support more TS transitions than one specific to the HD-PVR, so that may take a little longer. I'm going do all of that in Java since if it can be improved it will be more likely that someone might step up.

enternoescape commented 8 years ago

I ran into a few channels that have 3 audio tracks that are showing up as audio only. I'm having a hard time figuring out how to send a hint to detection that I need at least one video and one audio track. Any suggestions on where I should look to fix this?

Narflex commented 8 years ago

I'm not sure I understand exactly what you mean....but are you saying that it's not detecting the video stream on some channels? If so, do you have the Native.log from when that occurs? (I think I know what this one is and can help you resolve it)

Jeff Kardatzke Sent from my Android On Jun 8, 2016 10:21 AM, "Joseph Shuttlesworth" notifications@github.com wrote:

I ran into a few channels that have 3 audio tracks that are showing up as audio only. I'm having a hard time figuring out how to send a hint to detection that I need at least one video and one audio track. Any suggestions on where I should look to fix this?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-224604607, or mute the thread https://github.com/notifications/unsubscribe/ANEIDOIBEb-sIqAfeZXqTLI9Z1rugQ_4ks5qJs_9gaJpZM4IeL_U .

enternoescape commented 8 years ago

Yes, the video is not being detected on some channels. Actually I just noticed that one of the audio streams is missing on one of them too. The attached log for a TS that has 1 video and 3 audio streams.

Native.log.txt

Here's the output from RemuxFile.exe run on another file from the same channel. The output looks very similar and it only wrote out the same two languages as the other log. I thought it might be nice to have a reference that should be free of any errors I could have made.

RemuxFile.txt

Narflex commented 8 years ago

That's not the issue I was thinking of. Can you post a small TS file that can reproduce the issue with SageTV format detection? Be aware I also made a change recently which will use FFMPEG in this case to workaround a problem relating to this.

That also reminds me....when I was looking at that other problem before, I swore I was editing code in native/ax/Native2.0 for debugging the format detector...I think the Java lib may only use the old code for remuxing, but the new code for format detection.

Jeff Kardatzke Sent from my Android On Jun 8, 2016 11:13 AM, "Joseph Shuttlesworth" notifications@github.com wrote:

Yes, the video is not being detected on some channels. Actually I just noticed that one of the audio tracks is missing on one of them too. The attached log for a TS that has 1 video and 3 audio streams.

Native.log.txt https://github.com/google/sagetv/files/305079/Native.log.txt

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-224621207, or mute the thread https://github.com/notifications/unsubscribe/ANEIDAxagPIqjwGzlTM6JEdA1Dhp3NM9ks5qJtv9gaJpZM4IeL_U .

enternoescape commented 8 years ago

That's entirely possible. I didn't want to break anything that's not already broken in my adventures, so I figured it was safer to err on the side of caution when I noticed for example that the wizard was using it.

Here's a link to the file I ran through FileRemux.exe; it's two minutes: https://drive.google.com/open?id=0B4AD2tiek6Xic0N0di00SU9tMTA

I took a look at your last commit. This could be related, but I wouldn't really be able to fix it the way you did in Java.

Narflex commented 8 years ago

OK, cool...the first Native.log you posted didn't have what I was looking for (it appears there were only audio streams in that one). But the file you posted, and the output from RemuxFile that you posted both have what I wanted to see (i.e., I understand the problem).

There's this part in there for the video stream:

Type:0x80 Pid:0xbc3

The 0x80 type is DC-II, and it's been a problematic one. That type isn't really definitive overall, as we've seen it be non-video in imported files before. However, there's logic in the format detection code where if it has a 'hint' that it's analyzing a TV source, then it will assume that the 0x80 type is for video and then the format detection should come out correct.

The fix for you shouldn't be that bad to do at all. I'm not sure where you want to put it because I don't know where exactly you are tying into the remuxer...but I'll walk you through the origin of it so you can decide where to fix it.

The fix lies in ax/Native2.0/NativeCore/TSFilter.c in the conditional on line 1510. The stream type is 0x80, so it's passing those parts...but the DCII and Video Desc tags are not in the stream. So you're relying on the inner part of the conditional where it checks for 0x80 type and that IsTVMedia(nMediaType) is true. So the way to fix it is to ensure that IsTVMedia(nMediaType) is true (and it's safe to do that, because you are analyzing a TV recording).

SelectTSFilterChannel gets called from TSParser.c in various places, and it always takes that media type from pTSParser->media_type. There's a couple ways you could get that set...if the TUNE parameter passed through everywhere is set properly, then the media_type will get set to TV in OpenTSChannel. Alternatively, you can set the media type directly in the TSParser pointer in the DEMUXER struct. At a higher level, I'd recommend passing a boolean down from Java that specifies whether or not the remuxer is analyzing a TV Recording (which is easy to determine from MMC.getInstance().isRecording(java.io.File)).

Hopefully that'll fix it all right up for you. :) If you need more info, just let me know.

enternoescape commented 8 years ago

Fantastic. After I followed the code you were referring to, suddenly everything made sense. I was able to configure the TUNE parameter to get the desired result. I had a feeling that was key to get this to work, but I had a lot of trouble figuring out what needed to be set to make it realize that I was tuning TV. Thanks for the great assistance. :)

Narflex commented 8 years ago

Glad you got it working. :) I'm always here to help.

On Thu, Jun 9, 2016 at 1:36 PM, Joseph Shuttlesworth < notifications@github.com> wrote:

Fantastic. After I followed the code you were referring to, suddenly everything made sense. I was able to configure the TUNE parameter to get the desired result. I had a feeling that was key to get this to work, but I had a lot of trouble figuring out what needed to be set to make it realize that I was tuning TV. Thanks for the great assistance. :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sagetv/issues/138#issuecomment-225018324, or mute the thread https://github.com/notifications/unsubscribe/ANEIDCRY5kumdjxTV3VIY-HuXIWjxUPzks5qKHk2gaJpZM4IeL_U .

Jeffrey Kardatzke jkardatzke@google.com Google, Inc.